From cb2e26503a7540638f4dbc782276a5b963b12a90 Mon Sep 17 00:00:00 2001 From: poleli Date: Thu, 19 Dec 2024 13:26:45 +0800 Subject: [PATCH] [VideoTranslation][csharp] Simplify C# client sample code, upgrade to .net8.0 and support Linux for dotnet. (#2705) * Update video translation client sample code. * update namespace. * Update readme.md * Update option. * i * Make options class as partial. * Change class to partial. * Update app parameter. * Fix warning. * Fix warning. --------- Co-authored-by: Yulin Li --- .../DeploymentEnvironmentAttribute.cs | 61 - .../CommandParser/ArgumentAttribute.cs | 179 --- .../CommandParser/CommandLineParser.cs | 1281 ----------------- .../CommandParser/CommentAttribute.cs | 51 - .../CommonLib/CommandParser/ConsoleApp.cs | 59 - .../CommonLib/CommandParser/ExitCode.cs | 19 - .../CommonLib/CommandParser/InOutType.cs | 17 - .../csharp/Common/CommonLib/CommonConst.cs | 55 - .../csharp/Common/CommonLib/CommonLib.csproj | 23 - .../CommonLib/CustomContractResolver.cs | 143 -- .../DTOs/Public/VoiceGeneralTaskBrief.cs | 12 - .../Public/VoiceGeneralTaskInputFileBase.cs | 17 - .../Enums/VideoTranslationFileKind.cs | 15 - ...TranslationMergeParagraphAudioAlignKind.cs | 18 - .../Enums/VideoTranslationVoiceKind.cs | 20 - .../CommonLib/Extensions/EnumExtensions.cs | 21 - .../Extensions/FileNameExtensions.cs | 295 ---- .../CommonLib/Extensions/StringExtensions.cs | 54 - .../Common/CommonLib/HttpClientConfigBase.cs | 49 - .../csharp/Common/CommonLib/Readme.txt | 2 - .../Common/CommonLib/Util/ConsoleHelper.cs | 52 - .../CommonLib/Util/ConsoleMaskSasHelper.cs | 24 - .../Common/CommonLib/Util/EnumExtensions.cs | 58 - .../Common/CommonLib/Util/JsonHelper.cs | 70 - .../Common/CommonLib/Util/Sha256Helper.cs | 66 - .../CommonLib/Util/StringFormatHelper.cs | 17 - .../Common/CommonLib/Util/TaskNameHelper.cs | 61 - .../csharp/Common/CommonLib/Util/UriHelper.cs | 53 - .../Enum/DeploymentEnvironment.cs | 22 - .../VideoTranslationConstant.cs | 13 - .../ConsoleAppHelper.cs | 67 - .../Enum/VoiceKindExtensions.cs | 21 - .../Public-2024-05-20-preview/Iteration.cs | 28 - .../VideoTranslationLib.PublicPreview.csproj | 13 - ...ranslationPublicPreviewHttpClientConfig.cs | 42 - .../CommonLib.Public.csproj} | 10 +- .../CommonLib.Public/CommonPublicConst.cs | 77 + .../DTOs/Public/PaginatedResources.cs | 0 .../DataContracts/DTOs/Public/ResponseBase.cs | 0 .../DTOs/Public/StatefulResourceBase.cs | 3 +- .../DTOs/Public/StatelessResourceBase.cs | 0 .../Enums/OneApiState.cs | 4 +- .../HttpClient/ApimApiRegionConfig.cs | 23 + .../HttpClient}/HttpClientBase.cs | 90 +- .../HttpClient/HttpClientConfigBase.cs | 52 + .../CommonLib.Public/Interface/IAppLogger.cs | 15 + .../Interface/IRegionConfig.cs | 15 + .../Util/CommonHelper.cs | 35 +- .../Util/ExceptionHelper.cs | 0 .../CommonLib.Public/Util/PublicAppLogger.cs | 27 + .../Public-2024-05-20-preview/Iteration.cs | 15 + .../IterationInput.cs | 2 +- .../IterationResult.cs | 2 +- .../PagedTranslation.cs | 2 +- .../Public-2024-05-20-preview/Translation.cs | 8 +- .../TranslationInput.cs | 2 +- .../VideoTranslationLib.Public.csproj | 28 + .../Enum/OperationStatus.cs | 0 .../Enum/VoiceKind.cs | 0 .../Enum/WebvttFileKind.cs | 0 .../Public-2024-05-20-preview/Operation.cs | 0 .../Public-2024-05-20-preview/WebvttFile.cs | 0 ...ranslationPublicPreviewHttpClientConfig.cs | 25 + .../VideoTranslationLib.PublicBase.csproj | 13 + .../HttpClient/IterationClient.cs | 22 +- .../HttpClient/OperationClient.cs | 23 +- .../HttpClient/TranslationClient.cs | 59 +- .../VideoTranslationSample.sln | 41 +- .../Options/BaseOptions.cs | 20 + ...eIterationAndWaitUntilTerminatedOptions.cs | 39 + ...rationAndWaitUntilTerminatedBaseOptions.cs | 26 + ...dIterationAndWaitUntilTerminatedOptions.cs | 17 + .../Options/CreateTranslationBaseOptions.cs | 39 + .../Options/CreateTranslationOptions.cs | 20 + .../Options/DeleteTranslationOptions.cs | 16 + .../Options/QueryIterationOptions.cs | 19 + .../Options/QueryIterationsOptions.cs | 16 + .../Options/QueryTranslationOptions.cs | 16 + .../Options/QueryTranslationsOptions.cs | 14 + .../csharp/VideoTranslationSample/Program.cs | 246 ++++ .../VideoTranslationSample.csproj | 24 + .../VideoTranslationSample/Arguments.cs | 230 --- .../VideoTranslationSample/Mode.cs | 29 - .../VideoTranslationSample/Program.cs | 198 --- .../VideoTranslationSample.csproj | 16 - samples/video-translation/csharp/readme.md | 110 +- samples/video-translation/python/readme.md | 12 +- 87 files changed, 1054 insertions(+), 3644 deletions(-) delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Attributes/DeploymentEnvironmentAttribute.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommandParser/ArgumentAttribute.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommandParser/CommandLineParser.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommandParser/CommentAttribute.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommandParser/ConsoleApp.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommandParser/ExitCode.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommandParser/InOutType.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommonConst.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CommonLib.csproj delete mode 100644 samples/video-translation/csharp/Common/CommonLib/CustomContractResolver.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskBrief.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskInputFileBase.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationFileKind.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationMergeParagraphAudioAlignKind.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationVoiceKind.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Extensions/EnumExtensions.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Extensions/FileNameExtensions.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Extensions/StringExtensions.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/HttpClientConfigBase.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Readme.txt delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/ConsoleHelper.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/ConsoleMaskSasHelper.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/EnumExtensions.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/JsonHelper.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/Sha256Helper.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/StringFormatHelper.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/TaskNameHelper.cs delete mode 100644 samples/video-translation/csharp/Common/CommonLib/Util/UriHelper.cs delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.Common/Enum/DeploymentEnvironment.cs delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationConstant.cs delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/ConsoleAppHelper.cs delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/VoiceKindExtensions.cs delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationLib.PublicPreview.csproj delete mode 100644 samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationPublicPreviewHttpClientConfig.cs rename samples/video-translation/csharp/{Common/VideoTranslationLib.Common/VideoTranslationLib.Common.csproj => CommonLib.Public/CommonLib.Public.csproj} (56%) create mode 100644 samples/video-translation/csharp/CommonLib.Public/CommonPublicConst.cs rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/DataContracts/DTOs/Public/PaginatedResources.cs (100%) rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/DataContracts/DTOs/Public/ResponseBase.cs (100%) rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/DataContracts/DTOs/Public/StatefulResourceBase.cs (81%) rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/DataContracts/DTOs/Public/StatelessResourceBase.cs (100%) rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/Enums/OneApiState.cs (87%) create mode 100644 samples/video-translation/csharp/CommonLib.Public/HttpClient/ApimApiRegionConfig.cs rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public/HttpClient}/HttpClientBase.cs (65%) create mode 100644 samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientConfigBase.cs create mode 100644 samples/video-translation/csharp/CommonLib.Public/Interface/IAppLogger.cs create mode 100644 samples/video-translation/csharp/CommonLib.Public/Interface/IRegionConfig.cs rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/Util/CommonHelper.cs (83%) rename samples/video-translation/csharp/{Common/CommonLib => CommonLib.Public}/Util/ExceptionHelper.cs (100%) create mode 100644 samples/video-translation/csharp/CommonLib.Public/Util/PublicAppLogger.cs create mode 100644 samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.Public}/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs (92%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.Public}/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs (93%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.Public}/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs (74%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.Public}/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs (53%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.Public}/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs (96%) create mode 100644 samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/VideoTranslationLib.Public.csproj rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview/DataContracts => VideoTranslationLib.Public/VideoTranslationLib.PublicBase}/DTOs/Public-2024-05-20-preview/Enum/OperationStatus.cs (100%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview/DataContracts => VideoTranslationLib.Public/VideoTranslationLib.PublicBase}/DTOs/Public-2024-05-20-preview/Enum/VoiceKind.cs (100%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview/DataContracts => VideoTranslationLib.Public/VideoTranslationLib.PublicBase}/DTOs/Public-2024-05-20-preview/Enum/WebvttFileKind.cs (100%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview/DataContracts => VideoTranslationLib.Public/VideoTranslationLib.PublicBase}/DTOs/Public-2024-05-20-preview/Operation.cs (100%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview/DataContracts => VideoTranslationLib.Public/VideoTranslationLib.PublicBase}/DTOs/Public-2024-05-20-preview/WebvttFile.cs (100%) create mode 100644 samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/HttpClient/VideoTranslationPublicPreviewHttpClientConfig.cs create mode 100644 samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/VideoTranslationLib.PublicBase.csproj rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles}/HttpClient/IterationClient.cs (90%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles}/HttpClient/OperationClient.cs (75%) rename samples/video-translation/csharp/{Common/VideoTranslationLib.PublicPreview => VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles}/HttpClient/TranslationClient.cs (72%) rename samples/video-translation/csharp/{VideoTranslationSample => }/VideoTranslationSample.sln (51%) create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/BaseOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/CreateIterationAndWaitUntilTerminatedOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedBaseOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationBaseOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/DeleteTranslationOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationsOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationsOptions.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/Program.cs create mode 100644 samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.csproj delete mode 100644 samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Arguments.cs delete mode 100644 samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Mode.cs delete mode 100644 samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Program.cs delete mode 100644 samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/VideoTranslationSample.csproj diff --git a/samples/video-translation/csharp/Common/CommonLib/Attributes/DeploymentEnvironmentAttribute.cs b/samples/video-translation/csharp/Common/CommonLib/Attributes/DeploymentEnvironmentAttribute.cs deleted file mode 100644 index 621612a0d..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Attributes/DeploymentEnvironmentAttribute.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Attributes; - -using Microsoft.SpeechServices.CommonLib.Extensions; -using System; -using System.IO; - -[AttributeUsage(AttributeTargets.Field, Inherited = false, AllowMultiple = false)] -public sealed class DeploymentEnvironmentAttribute : Attribute -{ - public DeploymentEnvironmentAttribute( - string regionIdentifier) - { - this.RegionIdentifier = regionIdentifier; - } - - public string RegionIdentifier { get; internal set; } - - public string ApimHostName - { - get - { - return $"{this.RegionIdentifier}.api.cognitive.microsoft.com"; - } - } - - public static TDeploymentEnvironment ParseFromRegionIdentifier(string regionIdentifier) - where TDeploymentEnvironment : Enum - { - if (string.IsNullOrEmpty(regionIdentifier)) - { - throw new ArgumentNullException(nameof(regionIdentifier)); - } - - foreach (TDeploymentEnvironment environment in Enum.GetValues(typeof(TDeploymentEnvironment))) - { - var attribute = environment.GetAttributeOfType(); - if (string.Equals(attribute?.RegionIdentifier, regionIdentifier, StringComparison.OrdinalIgnoreCase)) - { - return environment; - } - } - - throw new NotSupportedException($"Not supported region: {regionIdentifier}"); - } - - public Uri GetApimApiBaseUrl() - { - Uri url = null; - if (!string.IsNullOrEmpty(this.ApimHostName)) - { - url = new Uri($"https://{this.ApimHostName}/"); - } - - return url; - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/CommandParser/ArgumentAttribute.cs b/samples/video-translation/csharp/Common/CommonLib/CommandParser/ArgumentAttribute.cs deleted file mode 100644 index e12c179d2..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommandParser/ArgumentAttribute.cs +++ /dev/null @@ -1,179 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.CommandParser; - -using System; -using System.Globalization; - -[AttributeUsage(AttributeTargets.Field, Inherited = false)] -public sealed class ArgumentAttribute : Attribute -{ - private readonly string flag; - private string description = string.Empty; - private string usagePlaceholder; - private bool optional; - private bool hidden; - private InOutType inoutType; - private string requiredModes; - private string optionalModes; - - /// - /// Initializes a new instance of the class. - /// - /// Flag string for this attribute. - public ArgumentAttribute(string optionName) - { - if (optionName == null) - { - throw new ArgumentNullException(nameof(optionName)); - } - - this.flag = optionName; - } - - /// - /// Gets The parse recognising flag. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Ignore.")] - public string OptionName - { - get { return this.flag.ToLower(CultureInfo.InvariantCulture); } - } - - /// - /// Gets or sets Description will display in the PrintUsage method. - /// - public string Description - { - get - { - return this.description; - } - - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - this.description = value; - } - } - - /// - /// Gets or sets In the PrintUsage method this will display a place hold for a parameter. - /// - public string UsagePlaceholder - { - get - { - return this.usagePlaceholder; - } - - set - { - if (value == null) - { - throw new ArgumentNullException(nameof(value)); - } - - this.usagePlaceholder = value; - } - } - - /// - /// Gets or sets a value indicating whether (optional = true) means not necessarily in the command-line. - /// - public bool Optional - { - get { return this.optional; } - set { this.optional = value; } - } - - /// - /// Gets or sets a value indicating whether (Hidden = true) means this option will not be printed in the command-line. - /// While one option is set with Hidden, the Optional must be true. - /// - public bool Hidden - { - get { return this.hidden; } - set { this.hidden = value; } - } - - /// - /// Gets or sets The in/out type of argument. - /// - public InOutType InOutType - { - get { return this.inoutType; } - set { this.inoutType = value; } - } - - /// - /// Gets or sets The modes require this argument. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Ignore.")] - public string RequiredModes - { - get - { - return this.requiredModes; - } - - set - { - this.requiredModes = value?.ToLower(CultureInfo.InvariantCulture); - } - } - - /// - /// Gets or sets The modes optionally require this argument. - /// - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Ignore.")] - public string OptionalModes - { - get - { - return this.optionalModes; - } - - set - { - this.optionalModes = value?.ToLower(CultureInfo.InvariantCulture); - } - } - - /// - /// Get required modes in an array. - /// - /// Mode array. - public string[] GetRequiredModeArray() - { - string[] modes = null; - if (!string.IsNullOrEmpty(this.requiredModes)) - { - modes = this.requiredModes.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - } - - return modes; - } - - /// - /// Get optional modes in an array. - /// - /// Mode array. - public string[] GetOptionalModeArray() - { - string[] modes = null; - if (!string.IsNullOrEmpty(this.optionalModes)) - { - modes = this.optionalModes.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); - } - - return modes; - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/CommandParser/CommandLineParser.cs b/samples/video-translation/csharp/Common/CommonLib/CommandParser/CommandLineParser.cs deleted file mode 100644 index bd404a9ec..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommandParser/CommandLineParser.cs +++ /dev/null @@ -1,1281 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.CommandParser; - -using System; -using System.Collections; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Reflection; -using System.Runtime.Serialization; -using System.Security.Permissions; -using System.Text; - -public static class CommandLineParser -{ - public static void Parse(string[] args, object target) - { - ClpHelper.CheckTarget(target); - ClpHelper.CheckArgs(args, target); - - InternalFlags internalTarget = new InternalFlags(); - ClpHelper helper = new ClpHelper(target, internalTarget); - - helper.ParseArgs(args); - - if (!string.IsNullOrEmpty(internalTarget.ConfigFile)) - { - args = ClpHelper.GetStringsFromConfigFile(internalTarget.ConfigFile); - helper.ParseArgs(args); - } - - if (internalTarget.NeedHelp) - { - throw new CommandLineParseException(string.Empty, "help"); - } - - helper.CheckAllRequiredDestination(); - } - - public static void PrintUsage(object target) - { - string usage = BuildUsage(target); - Console.WriteLine(); - Console.WriteLine(usage); - } - - public static void HandleException(object target, Exception exception) - { - ArgumentNullException.ThrowIfNull(exception); - if (!string.IsNullOrEmpty(exception.Message)) - { - ArgumentNullException.ThrowIfNull(exception.Message); - } - else - { - PrintUsage(target); - } - } - - public static string BuildUsage(object target) - { - ClpHelper.CheckTarget(target); - - CommentAttribute[] ca = (CommentAttribute[])target.GetType().GetCustomAttributes(typeof(CommentAttribute), false); - - StringBuilder sb = new StringBuilder(); - - if (ca.Length == 1 && !string.IsNullOrEmpty(ca[0].HeadComment)) - { - sb.AppendLine(ca[0].HeadComment); - } - - sb.AppendLine(); - - Assembly entryAssm = Assembly.GetEntryAssembly(); - - // entryAssm is a null reference when a managed assembly has been loaded - // from an unmanaged application; Currently we don't allow such calling. - // But when calling by our Nunit test framework, this value is null - if (entryAssm != null) - { - sb.AppendFormat(CultureInfo.InvariantCulture, "Version {0}", entryAssm.GetName().Version.ToString()); - sb.AppendLine(); - } - - sb.Append(ClpHelper.BuildUsageLine(target)); - sb.Append(ClpHelper.BuildOptionsString(target)); - - if (ca.Length == 1 && !string.IsNullOrEmpty(ca[0].RearComment)) - { - sb.AppendLine(); - sb.AppendLine(ca[0].RearComment); - } - - return sb.ToString(); - } - - /// - /// Command line parser helper class. - /// - private class ClpHelper - { - public const BindingFlags AllFieldBindingFlags = - BindingFlags.Instance | BindingFlags.Static | - BindingFlags.Public | BindingFlags.NonPublic | - BindingFlags.DeclaredOnly; - - public const string Mode = "mode"; - - // const members. - private const int MaxCommandLineStringNumber = 800; - private const int MaxConfigFileSize = 32 * 1024; // 32k - - private string modeString; - - // class members. - private object clpTarget; - private InternalFlags internalTarget; - private Dictionary destMap = new Dictionary(); - - /// - /// Initializes a new instance of the class. - /// - /// Target object to reflect usage information. - /// Internal flags. - public ClpHelper(object target, InternalFlags internalTarget) - { - this.clpTarget = target; - this.internalTarget = internalTarget; // interal flags class, include "-h","-?","-help","-C" - - this.ParseTheDestination(target); - } - - /// - /// Check the target objcet, which is to save the value, to avoid misuse. - /// - /// Target object to reflect usage information. - public static void CheckTarget(object target) - { - if (target == null) - { - throw new ArgumentNullException(nameof(target)); - } - - if (!target.GetType().IsClass) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Object target is not a class."), "target"); - } - - // Check each field of the target class to ensure that every field, which wanted to be - // filled, has defined a static TryParse(string, out Value) funtion. In the parsing time, - // the CLP class will use this static function to parse the string to value. - foreach (FieldInfo fieldInfo in target.GetType().GetFields(ClpHelper.AllFieldBindingFlags)) - { - if (fieldInfo.IsDefined(typeof(ArgumentAttribute), false)) - { - Type type = fieldInfo.FieldType; - if (type.IsArray) - { - type = type.GetElementType(); - } - - // string Type don't need a TryParse function, so skip check it. - if (type == typeof(string)) - { - continue; - } - - Type reftype = Type.GetType(type.ToString() + "&"); - if (reftype == null) - { - throw new ArgumentException( - "This Type does not exist in this assembly GetType(" + type + ")failed.", - fieldInfo.ToString()); - } - - MethodInfo mi = type.GetMethod("TryParse", new Type[] { typeof(string), reftype }); - if (mi == null) - { - throw new ArgumentException( - "Type " + type + " don't have a TryParse(string, out Value) method.", - fieldInfo.ToString()); - } - } - } - } - - /// - /// Check args from static Main() function, to avoid misuse this library. - /// - /// Argument string array. - /// Target object to reflect usage information. - public static void CheckArgs(string[] args, object target) - { - if (args == null) - { - string message = string.Format(CultureInfo.InvariantCulture, "Empty parameters."); - throw new CommandLineParseException(message); - } - - int requiredArgumentCount = GetRequiredArgumentCount(target); - if (args.Length == 0) - { - // if there is no parameter given - if (requiredArgumentCount > 0) - { - // some parameters are required - throw new CommandLineParseException(string.Empty, "help"); - } - - // run the application with default option values - } - - if (args.Length > MaxCommandLineStringNumber) - { - throw new CommandLineParseException(string.Format(CultureInfo.InvariantCulture, "Input parameter number is larger than {0}.", MaxCommandLineStringNumber), "args"); - } - - for (int i = 0; i < args.Length; ++i) - { - if (string.IsNullOrEmpty(args[i])) - { - string message = string.Format(CultureInfo.InvariantCulture, "The {0}(th) parameter in the command line could not be null or empty.", i + 1); - throw new CommandLineParseException(message); - } - } - } - - /// - /// Parse the configuration file into a string[], this string[] will be send to the - /// ParseArgs(string[] args). This function will do some simple check of the - /// Command line, the first character the config line in the file must '-', - /// Otherwise, this line will not be parsed. - /// - /// Configuration file path. - /// Configuration strings. - public static string[] GetStringsFromConfigFile(string filePath) - { - if (!File.Exists(filePath)) - { - string message = string.Format(CultureInfo.InvariantCulture, "The configuration file [{0}] can not found.", filePath); - throw new CommandLineParseException(message, filePath); - } - - FileInfo fileInfo = new FileInfo(filePath); - - if (fileInfo.Length > MaxConfigFileSize) - { - string message = string.Format(CultureInfo.InvariantCulture, "Not supported configuration file [{0}], for the size of it is bigger than {1} byte.", filePath, MaxConfigFileSize); - throw new CommandLineParseException(message, filePath); - } - - string[] lines; - using (StreamReader streamFile = new StreamReader(filePath)) - { - lines = streamFile.ReadToEnd().Split(Environment.NewLine.ToCharArray()); - } - - List strList = new List(); - - // Go through the file, and expand the listed parameters - // into the List of existing parameters. - foreach (string line in lines) - { - string trimedLine = line.Trim(); - - if (trimedLine.IndexOf('-') == 0) - { - string[] strArray = trimedLine.Split(new char[] { ' ', '\t' }); - foreach (string str in strArray) - { - if (!string.IsNullOrEmpty(str)) - { - strList.Add(str); - } - } - } - } - - return strList.ToArray(); - } - - /// - /// Count the number of required arguments. - /// - /// Target object to reflect usage information. - /// The number of required arguments. - public static int GetRequiredArgumentCount(object target) - { - int count = 0; - foreach (FieldInfo field in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(field); - if (argument == null) - { - continue; // skip those field that don't define the ArgumentAttribute. - } - - if (!argument.Optional) - { - count++; - } - } - - return count; - } - - /// - /// Build the useage line. First print the file name of current execution files. - /// And then, print the each flag of these options. - /// - /// Target object to reflect usage information. - /// Useage string. - public static string BuildUsageLine(object target) - { - StringBuilder sb = new StringBuilder(); - sb.AppendFormat(CultureInfo.InvariantCulture, "Usage:{0}", Environment.NewLine); - - string[] allModes = GetAllModes(target); - if (allModes != null) - { - foreach (string mode in allModes) - { - sb.AppendFormat(CultureInfo.InvariantCulture, @" Mode ""{0}"" has following usage: {1}", mode, Environment.NewLine); - sb.AppendFormat(CultureInfo.InvariantCulture, " {0} -mode {1}", AppDomain.CurrentDomain.FriendlyName, mode); - - foreach (FieldInfo field in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(field); - if (argument == null) - { - continue; // skip those field that don't define the ArgumentAttribute. - } - - if (argument.OptionName == ClpHelper.Mode) - { - continue; - } - - string[] optionalModes = argument.GetOptionalModeArray(); - string[] requiredModes = argument.GetRequiredModeArray(); - if (requiredModes == null && optionalModes == null) - { - // should not print out hidden argument - if (!argument.Hidden) - { - if (argument.Optional) - { - sb.AppendFormat(CultureInfo.InvariantCulture, " [{0}]", GetFlagAndPlaceHolderString(argument)); - } - else - { - sb.AppendFormat(CultureInfo.InvariantCulture, " {0}", GetFlagAndPlaceHolderString(argument)); - } - } - } - else - { - if ((optionalModes != null) && IsInArray(optionalModes, mode)) - { - sb.AppendFormat(CultureInfo.InvariantCulture, " [{0}]", GetFlagAndPlaceHolderString(argument)); - } - else if (requiredModes != null && IsInArray(requiredModes, mode)) - { - sb.AppendFormat(CultureInfo.InvariantCulture, " {0}", GetFlagAndPlaceHolderString(argument)); - } - } - } - - sb.AppendLine(string.Empty); - sb.AppendLine(string.Empty); - } - } - else - { - sb.AppendFormat(CultureInfo.InvariantCulture, " {0}", AppDomain.CurrentDomain.FriendlyName); - - foreach (FieldInfo field in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(field); - if (argument == null) - { - continue; // skip those field that don't define the ArgumentAttribute. - } - - string optionLine = BuildOptionLine(argument); - sb.Append(optionLine); - } - } - - sb.AppendLine(); - sb.AppendLine(); - - return sb.ToString(); - } - - /// - /// Print flag and description of each options. - /// - /// Target object to reflect usage information. - /// Flag and description string of each options. - public static string BuildOptionsString(object target) - { - StringBuilder sb = new StringBuilder(); - sb.AppendLine(" Options\tDescriptions"); - sb.Append(BuildOptionsString(target, null)); - return sb.ToString(); - } - - /// - /// Parse the args string from the static Main() or from configuration file. - /// - /// Argument string array. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Ignore.")] - public void ParseArgs(string[] args) - { - Destination destination = null; - - foreach (string str in args) - { - Destination dest = this.IsFlagStringAndGetTheDestination(str); - - // Is a flag string - if (dest != null) - { - if (destination != null) - { - destination.Save(this.clpTarget); - } - - destination = dest; - - if (destination.AlreadySaved) - { - string message = string.Format(CultureInfo.InvariantCulture, "The option flag [-{0}] could not be dupalicated.", destination.Argument.OptionName); - throw new CommandLineParseException(message, str); - } - } - else - { - if (destination == null) - { - destination = this.SaveValueStringToEmptyFlag(str); - } - else - { - if (!destination.TryToAddValue(this.clpTarget, str)) - { - destination.Save(this.clpTarget); - destination = this.SaveValueStringToEmptyFlag(str); - } - } - - if (destination != null) - { - if (destination.Argument.OptionName == ClpHelper.Mode) - { - this.modeString = str.ToLower(CultureInfo.InvariantCulture); - } - } - } - } - - // deal with the last flag - if (destination != null) - { - destination.Save(this.clpTarget); - } - } - - /// - /// By the end of the command line parsing, we must make sure that all non-optional - /// Flags have been given by the tool user. - /// - public void CheckAllRequiredDestination() - { - string[] allModes = GetAllModes(this.clpTarget); - foreach (Destination destination in this.destMap.Values) - { - bool requiredMissing = false; - if (destination.InternalTarget != null) - { - continue; - } - - if (allModes != null) - { - Debug.Assert(this.destMap.ContainsKey(Mode), "Failed"); - if (!string.IsNullOrEmpty(this.modeString)) - { - string[] requireModes = destination.Argument.GetRequiredModeArray(); - string[] optionalModes = destination.Argument.GetOptionalModeArray(); - if (requireModes == null) - { - if (optionalModes == null) - { - // if required modes and optional modes are all empty - // Means the argument is commonly optional or not in all modes. - // we can use the Optional flag to simplify - requiredMissing = !destination.Argument.Optional && !destination.AlreadySaved; - } - } - else - { - if (IsInArray(requireModes, this.modeString)) - { - requiredMissing = !destination.AlreadySaved; - } - } - - if (destination.AlreadySaved && (optionalModes != null || requireModes != null)) - { - if ((requireModes == null && !IsInArray(optionalModes, this.modeString)) || - (optionalModes == null && !IsInArray(requireModes, this.modeString)) || - (requireModes != null && optionalModes != null && - !IsInArray(optionalModes, this.modeString) && !IsInArray(requireModes, this.modeString))) - { - string message = string.Format(CultureInfo.InvariantCulture, "Parameter [{0}] is not needed for mode [{1}].", destination.Argument.OptionName, this.modeString); - throw new CommandLineParseException(message); - } - } - } - else - { - string message = string.Format(CultureInfo.InvariantCulture, "The mode option is required for the command."); - throw new CommandLineParseException(message); - } - } - else - { - requiredMissing = !destination.Argument.Optional && !destination.AlreadySaved; - } - - if (requiredMissing) - { - string optionLine = BuildOptionLine(destination.Argument); - string message = string.Format(CultureInfo.InvariantCulture, "The option '{0}' is required for the command.", optionLine.Trim()); - throw new CommandLineParseException(message, "-" + destination.Argument.OptionName); - } - } - } - - /// - /// Check if a value is in array. - /// - /// Array. - /// Value. - /// Boolean. - private static bool IsInArray(string[] arr, string value) - { - bool found = false; - for (int i = 0; i < arr.Length; i++) - { - if (arr[i] == value) - { - found = true; - break; - } - } - - return found; - } - - private static void CheckModeArray(string[] totalModes, string[] modes) - { - ArgumentNullException.ThrowIfNull(totalModes); - if (modes == null) - { - return; - } - - string msg = "Mode {0} should be listed in mode argument's Modes string."; - if (modes != null) - { - for (int i = 0; i < modes.Length; i++) - { - if (!IsInArray(totalModes, modes[i])) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, msg, modes[i])); - } - } - } - } - - private static string BuildOptionsString(object target, string mode) - { - StringBuilder sb = new StringBuilder(); - foreach (FieldInfo field in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(field); - if (argument == null) - { - continue; - } - - if (!string.IsNullOrEmpty(mode)) - { - string[] modeArray = argument.GetRequiredModeArray(); - if (modeArray != null) - { - bool found = IsInArray(modeArray, mode); - if (!found) - { - continue; - } - } - } - - if (!argument.Hidden) - { - string str = field.FieldType.ToString(); - int i = str.LastIndexOf('.'); - str = str.Substring(i == -1 ? 0 : i + 1); - - sb.AppendFormat(CultureInfo.InvariantCulture, " {0}{1}\t\t({3}) {2}", GetFlagAndPlaceHolderString(argument), Environment.NewLine, argument.Description, str); - if (argument.InOutType != InOutType.Unknown) - { - sb.AppendFormat(CultureInfo.InvariantCulture, " [{0}]", Enum.GetName(typeof(InOutType), argument.InOutType)); - } - - sb.Append(Environment.NewLine); - } - else - { - if (!argument.Optional) - { - string message = string.Format(CultureInfo.InvariantCulture, "Argument for {0} can be hidden but can not be optional at the meantime.", field.Name); - Debug.Assert(argument.Optional, message); - throw new ArgumentException(message); - } - } - } - - return sb.ToString(); - } - - private static string[] GetAllModes(object target) - { - ArgumentAttribute modeArgument = null; - foreach (FieldInfo field in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(field); - if (argument == null) - { - continue; - } - - if (argument.OptionName == ClpHelper.Mode) - { - modeArgument = argument; - break; - } - } - - if (modeArgument == null) - { - return null; - } - - string[] modeArray = modeArgument.GetRequiredModeArray(); - if (modeArray == null || modeArray.Length == 0) - { - return null; - } - - foreach (FieldInfo fieldInfo in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(fieldInfo); - if (argument == null) - { - continue; - } - - string[] requiredModes = argument.GetRequiredModeArray(); - string[] optionalModes = argument.GetOptionalModeArray(); - CheckModeArray(modeArray, requiredModes); - CheckModeArray(modeArray, optionalModes); - if (requiredModes != null && optionalModes != null) - { - for (int i = 0; i < requiredModes.Length; i++) - { - if (IsInArray(optionalModes, requiredModes[i])) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Required modes {0} is conflicted with optional modes {1}", argument.RequiredModes, argument.OptionalModes)); - } - } - } - } - - return modeArray; - } - - private static string BuildOptionLine(ArgumentAttribute argument) - { - StringBuilder sb = new StringBuilder(); - if (!argument.Hidden) - { - if (argument.Optional) - { - sb.AppendFormat(CultureInfo.InvariantCulture, " [{0}]", GetFlagAndPlaceHolderString(argument)); - } - else - { - sb.AppendFormat(CultureInfo.InvariantCulture, " {0}", GetFlagAndPlaceHolderString(argument)); - } - } - else - { - if (!argument.Optional) - { - string message = string.Format(CultureInfo.InvariantCulture, "Argument for -{0} can be hidden but can not be optional at the meantime.", argument.OptionName); - Debug.Assert(argument.Optional, message); - throw new ArgumentException(message); - } - } - - return sb.ToString(); - } - - /// - /// Get the ArgumentAttribute from the field. If the field don't define this - /// Custom attribute, it will return null. - /// - /// Field information. - /// Argument attribute associated with the field. - private static ArgumentAttribute GetFieldArgumentAttribute(FieldInfo fieldInfo) - { - ArgumentAttribute[] argument = - (ArgumentAttribute[])fieldInfo.GetCustomAttributes(typeof(ArgumentAttribute), false); - - return argument.Length == 1 ? argument[0] : null; - } - - /// - /// When output the usage, this function will generate the flag string - /// Such as "-time n1 n2..." string. - /// - /// Argument attribute. - /// Argument presentation on command line. - private static string GetFlagAndPlaceHolderString(ArgumentAttribute argument) - { - return (!string.IsNullOrEmpty(argument.OptionName) ? "-" : string.Empty) + - argument.OptionName + - (string.IsNullOrEmpty(argument.UsagePlaceholder) ? - string.Empty : " " + argument.UsagePlaceholder); - } - - /// - /// Call by the GetFlagAndPlaceHolderString() function, and generate the frendly - /// Name of each parameter in command line, such as "n1 n2 ..." string. - /// - /// Field information. - /// Field name of the argument. - private static string GetFieldFriendlyTypeName(FieldInfo fieldInfo) - { - Type type = fieldInfo.FieldType.IsArray ? - fieldInfo.FieldType.GetElementType() : fieldInfo.FieldType; - - string str; - if (type == typeof(bool)) - { - str = string.Empty; - } - else - { - // Use the Type name's first character, - // for example: System.int -> i, System.double -> d - str = type.ToString(); - int i = str.LastIndexOf('.'); - i = i == -1 ? 0 : i + 1; - str = char.ToLower(str[i], CultureInfo.CurrentCulture).ToString(); - } - - return fieldInfo.FieldType.IsArray ? str + "1 " + str + "2 ..." : str; - } - - /// - /// Check and parse the internal target and external target, then push the result - /// Of parsing into the DestMap. - /// Internal target class has predefined some flags, such as "-h", "-C" - /// External target class are defined by the library users. - /// - /// Target object to reflect usage information. - private void ParseTheDestination(object target) - { - // Check and parse the internal target, so use Debug.Assert to catch the error. - foreach (FieldInfo fieldInfo in typeof(InternalFlags).GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(fieldInfo); - if (string.IsNullOrEmpty(argument.UsagePlaceholder)) - { - argument.UsagePlaceholder = GetFieldFriendlyTypeName(fieldInfo); - } - - Debug.Assert(argument != null, "Failed"); - - Destination destination = new Destination(fieldInfo, argument, this.internalTarget); - - Debug.Assert(destination.Argument.OptionName.Length != 0, "Failed"); - Debug.Assert(char.IsLetter(destination.Argument.OptionName[0]) || destination.Argument.OptionName[0] == '?', "Failed"); - - // Assert there is no duplicate flag in the user defined argument class. - Debug.Assert(!this.destMap.ContainsKey(destination.Argument.OptionName), "Failed"); - - this.destMap.Add(destination.Argument.OptionName, destination); - } - - // Check and parse the external target, so use throw exception - // to handle the unexpect target difine. - foreach (FieldInfo fieldInfo in target.GetType().GetFields(AllFieldBindingFlags)) - { - ArgumentAttribute argument = GetFieldArgumentAttribute(fieldInfo); - if (argument == null) - { - continue; - } - - Destination destination = new Destination(fieldInfo, argument, null); - - // Assert user don't define a non-letter as a flag in the user defined argument class. - if (destination.Argument.OptionName.Length > 0 && !char.IsLetter(destination.Argument.OptionName[0])) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "User can't define a non-letter flag ({0}).", destination.Argument.OptionName[0]), destination.Argument.OptionName[0].ToString()); - } - - // Assert there is no duplicate flag in the user defined argument class. - if (this.destMap.ContainsKey(destination.Argument.OptionName)) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "Duplicate flag are defined in the argument class."), destination.Argument.OptionName); - } - - this.destMap.Add(destination.Argument.OptionName, destination); - } - } - - /// - /// Check the given string is a flag, if so, get the corresponding destination class of the flag. - /// - /// String to test. - /// Destination. - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Ignore.")] - private Destination IsFlagStringAndGetTheDestination(string str) - { - Debug.Assert(!string.IsNullOrEmpty(str), "Failed"); - - if (str.Length < 2 || str[0] != '-' - || (!char.IsLetter(str[1]) && str[1] != '?')) - { - return null; - } - - str = str.Substring(1).ToLower(CultureInfo.InvariantCulture); - return this.destMap.ContainsKey(str) ? this.destMap[str] : null; - } - - /// - /// Save the given string to the empty flag("") destination class. - /// - /// Flag string to save, not the realy null Flag, is the "" Flag. - /// Destination. - private Destination SaveValueStringToEmptyFlag(string str) - { - Destination destination = this.destMap.ContainsKey(string.Empty) ? this.destMap[string.Empty] : null; - - if (destination == null || destination.AlreadySaved || - !destination.TryToAddValue(this.clpTarget, str)) - { - StringBuilder sb = new StringBuilder(); - sb.Append($"Unrecognized command {str}. "); - - Assembly assembly = Assembly.GetEntryAssembly(); - if (assembly != null) - { - sb.Append($"Run '{Path.GetFileName(assembly.Location)} -?' for help."); - } - - throw new CommandLineParseException(sb.ToString(), str); - } - - return destination; - } - } - - /// - /// Private class, to hold the information of the target object. - /// - private class Destination - { - private FieldInfo fieldInfo; - private ArgumentAttribute argument; - - // Hold the internal target, it distinguish - private InternalFlags internalTarget; - private bool alreadySaved; - - // A internal target to a external target. If it is external, this member is null. - private ArrayList parameterList; - - /// - /// Initializes a new instance of the class. - /// - /// Field information. - /// Argument attribute. - /// Internal flags. - public Destination(FieldInfo fieldInfo, ArgumentAttribute argument, InternalFlags internalTarget) - { - this.fieldInfo = fieldInfo; - this.argument = argument; - this.internalTarget = internalTarget; - - // _AlreadySaved = false; - this.parameterList = fieldInfo.FieldType.IsArray ? new ArrayList() : null; - } - - /// - /// Gets internal target. - /// - public InternalFlags InternalTarget - { - get { return this.internalTarget; } - } - - /// - /// Gets Argument attribute. - /// - public ArgumentAttribute Argument - { - get { return this.argument; } - } - - /// - /// Gets a value indicating whether Value already saved. - /// - public bool AlreadySaved - { - get { return this.alreadySaved; } - } - - /// - /// Parse the string to given type of value. - /// - /// Type of value. - /// String to parse. - /// Result value. - public static object TryParseStringToValue(Type type, string str) - { - object obj = null; - - if (type == typeof(string)) - { - // string to string, don't need parse. - obj = str; - } - else if (type == typeof(sbyte) || type == typeof(byte) || - type == typeof(short) || type == typeof(ushort) || - type == typeof(int) || type == typeof(uint) || - type == typeof(long) || type == typeof(ulong)) - { - // Use the dec style to parse the string into integer value frist. - // If it failed, then use the hex sytle to parse it again. - obj = TryParse(str, type, NumberStyles.Integer | NumberStyles.AllowThousands); - if (obj == null && str.Substring(0, 2) == "0x") - { - obj = TryParse(str.Substring(2), type, NumberStyles.HexNumber); - } - } - else if (type == typeof(double) || type == typeof(float)) - { - // Use float style to parse the string into float value. - obj = TryParse(str, type, NumberStyles.Float | NumberStyles.AllowThousands); - } - else - { - // Use the default style to parse the string. - obj = TryParse(str, type); - } - - return obj; - } - - /// - /// Try to and a value to the target. Frist prase the string form parameter - /// To a given value. And then, save the value to a target field or a value - /// List. - /// - /// Target object to reflect usage information. - /// String value to add. - /// True if succeeded, otherwise false. - public bool TryToAddValue(object target, string str) - { - if (this.alreadySaved) - { - return false; - } - - if (this.internalTarget != null) - { - target = this.internalTarget; - } - - // If this field is an array, it will save the prased value into an value list. - // Otherwise, it will save the parse value to the field of the target directly. - if (this.fieldInfo.FieldType.IsArray) - { - object value = TryParseStringToValue(this.fieldInfo.FieldType.GetElementType(), str); - if (value == null) - { - return false; - } - - this.parameterList.Add(value); - } - else - { - object value = TryParseStringToValue(this.fieldInfo.FieldType, str); - if (value == null) - { - return false; - } - - this.fieldInfo.SetValue(target, value); - this.alreadySaved = true; - } - - return true; - } - - /// - /// Save function will do some cleanup of the value save. - /// - /// Target object to reflect usage information. - public void Save(object target) - { - if (this.internalTarget != null) - { - target = this.internalTarget; - } - - if (this.fieldInfo.FieldType.IsArray) - { - // When the filed is an array, this function will save all values in the ParameterList - // into the array field. - Debug.Assert(!this.alreadySaved, "Failed"); - Array array = (Array)this.fieldInfo.GetValue(target); - if (array != null && array.Length != this.parameterList.Count) - { - string message = string.Format(CultureInfo.InvariantCulture, "For option flag -{0}, the parameter number is {1}, which is not as expected {2}.", this.argument.OptionName, this.parameterList.Count, array.Length); - throw new CommandLineParseException(message, "-" + this.argument.OptionName); - } - - this.fieldInfo.SetValue(target, this.parameterList.ToArray(this.fieldInfo.FieldType.GetElementType())); - } - else if (this.fieldInfo.FieldType == typeof(bool)) - { - if (!this.alreadySaved) - { - bool b = (bool)this.fieldInfo.GetValue(target); - b = !b; - this.fieldInfo.SetValue(target, b); - } - } - else if (!this.alreadySaved) - { - // Other types do nothing, only check its already saved, - // beacuse the value must be saved in the TryToAddValue(); - string message = string.Format(CultureInfo.InvariantCulture, "The option flag [-{0}] needs {1} parameter.", this.argument.OptionName, this.argument.UsagePlaceholder); - throw new CommandLineParseException(message, "-" + this.argument.OptionName); - } - - this.alreadySaved = true; - } - - /// - /// Use the given style to parse the string to given type of value. - /// - /// String to parse. - /// Type of value. - /// Number styles. - /// Result value. - private static object TryParse(string str, Type type, NumberStyles ns) - { - // Use reflection to dynamic load the TryParse function of given type. - Type[] typeArgs = new Type[] - { - typeof(string), - typeof(NumberStyles), - typeof(IFormatProvider), - Type.GetType(type.ToString() + "&"), - }; - - MethodInfo mi = type.GetMethod("TryParse", typeArgs); - - // Initilze these four parameters of the Tryparse funtion. - object[] objArgs = new object[] - { - str, - ns, - CultureInfo.InvariantCulture, - Activator.CreateInstance(type), - }; - - return DoTryParse(mi, objArgs); - } - - /// - /// Use the defalut style to parse the string to given type of value. - /// - /// String to parse. - /// Type of value. - /// Result value. - private static object TryParse(string str, Type type) - { - // Use reflection to dynamic load the TryParse function of given type. - MethodInfo mi = type.GetMethod("TryParse", new Type[] { typeof(string), Type.GetType(type.ToString() + "&") }); - - // Initilze these two parameters of the Tryparse funtion. - object[] objArgs = new object[] { str, Activator.CreateInstance(type) }; - - return DoTryParse(mi, objArgs); - } - - /// - /// Run the TryParse function by the given method and parameters. - /// - /// Method information. - /// Method arguments. - /// Result value. - private static object DoTryParse(MethodInfo methodInfo, object[] methodArgs) - { - object retVal = methodInfo.Invoke(null, methodArgs); - - if (!(retVal is bool)) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "TryParse() method must return a bool value."), methodArgs[methodArgs.Length - 1].GetType().ToString()); - } - - // the last parameter of TryParse method is a reference of a value. - // Therefore, it will return the last value of the parameter array. - // If the TryParse function failed when parsing, this DoTryParse will - // return null. - return (bool)retVal ? methodArgs[methodArgs.Length - 1] : null; - } - } - - /// - /// This class is defined to take the internal flags, such as -h, -?, -C, and etc. - /// When the parse begin to parse the target object, it will parse is class's object - /// First. So, the parse can first put the internal flags into the DestMap to avoid - /// Library user redifined those flags. And When finish parsed all flags, The library - /// Will check the property NeedHelp to determinated those flags are appeared in the - /// Command line. - /// - private sealed class InternalFlags - { - [Argument("h", Description = "Help", Optional = true)] - private bool needHelp1; - - [Argument("?", Description = "Help", Optional = true)] - private bool needHelp2; - - [Argument("help", Description = "Help", Optional = true)] - private bool needHelp3; - - [Argument("conf", Description = "Configuration file", Optional = true)] - private string configFile; // use internal instead of private to avoid unusing warning. - - /// - /// Initializes a new instance of the class. - /// - public InternalFlags() - { - this.needHelp1 = this.needHelp2 = this.needHelp3 = false; - } - - /// - /// Gets a value indicating whether Flag indicating whether user requires help. - /// - public bool NeedHelp - { - get { return this.needHelp1 || this.needHelp2 || this.needHelp3; } - } - - /// - /// Gets or sets Configuration file path. - /// - public string ConfigFile - { - get { return this.configFile; } - set { this.configFile = value; } - } - } -} - -/// -/// When the CommandLineParser meet an unacceptabile command line -/// Parameter, it will throw the CommandLineParseException. If the -/// CLP meet another arguments error by anaylse the target object, -/// It will throw the ArgumentException defined by .NET framework. -/// -[Serializable] -#pragma warning disable SA1402 // File may only contain a single type -public class CommandLineParseException : Exception -#pragma warning restore SA1402 // File may only contain a single type -{ - /// - /// The error string is "help". - /// - public const string ErrorStringHelp = "help"; - - private readonly string errorString; - - /// - /// Initializes a new instance of the class. - /// - /// Message. - /// Error string. - public CommandLineParseException(string message, string error) - : base(message) - { - this.errorString = string.IsNullOrEmpty(error) ? string.Empty : error; - } - - /// - /// Initializes a new instance of the class. - /// - public CommandLineParseException() - : base() - { - this.errorString = string.Empty; - } - - /// - /// Initializes a new instance of the class. - /// - /// Message. - public CommandLineParseException(string message) - : base(message) - { - this.errorString = string.Empty; - } - - /// - /// Initializes a new instance of the class. - /// - /// Message. - /// Inner exception. - public CommandLineParseException(string message, Exception inner) - : base(message, inner) - { - this.errorString = string.Empty; - } - - /// - /// Initializes a new instance of the class. - /// - /// Serialization info. - /// Streaming context. - protected CommandLineParseException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - this.errorString = string.Empty; - } - - /// - /// Gets To save the error string. - /// - public string ErrorString - { - get { return this.errorString; } - } - - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - } -} \ No newline at end of file diff --git a/samples/video-translation/csharp/Common/CommonLib/CommandParser/CommentAttribute.cs b/samples/video-translation/csharp/Common/CommonLib/CommandParser/CommentAttribute.cs deleted file mode 100644 index 366e6a1b7..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommandParser/CommentAttribute.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.CommandParser; - -using System; - -[AttributeUsage(AttributeTargets.Class, Inherited = false)] -public sealed class CommentAttribute : Attribute -{ - private readonly string headComment; - private readonly string rearComment = "Copyright (C) Microsoft Corporation. All rights reserved."; - - public CommentAttribute(string headComment) - { - if (headComment == null) - { - throw new ArgumentNullException(nameof(headComment)); - } - - this.headComment = headComment; - } - - public CommentAttribute(string headComment, string rearComment) - { - if (headComment == null) - { - throw new ArgumentNullException(nameof(headComment)); - } - - if (rearComment == null) - { - throw new ArgumentNullException(nameof(rearComment)); - } - - this.headComment = headComment; - this.rearComment = rearComment; - } - - public string HeadComment - { - get { return this.headComment; } - } - - public string RearComment - { - get { return this.rearComment; } - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/CommandParser/ConsoleApp.cs b/samples/video-translation/csharp/Common/CommonLib/CommandParser/ConsoleApp.cs deleted file mode 100644 index af5eb90ee..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommandParser/ConsoleApp.cs +++ /dev/null @@ -1,59 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.CommandParser -{ - using System; - using System.IO; - using System.Text; - using System.Threading.Tasks; - - public static class ConsoleApp - where T : new() - { - public static async Task RunAsync(string[] arguments, Func> processAsync) - { - ArgumentNullException.ThrowIfNull(processAsync); - - ArgumentNullException.ThrowIfNull(arguments); - - int ret = ExitCode.NoError; - - T arg = new T(); - try - { - try - { - CommandLineParser.Parse(arguments, arg); - } - catch (CommandLineParseException cpe) - { - if (cpe.ErrorString == CommandLineParseException.ErrorStringHelp) - { - CommandLineParser.PrintUsage(arg); - } - else if (!string.IsNullOrEmpty(cpe.Message)) - { - Console.WriteLine(cpe.Message); - } - - return ExitCode.InvalidArgument; - } - - ret = await processAsync(arg).ConfigureAwait(false); - return ret; - } - catch (Exception) - { - if (ret != ExitCode.NoError) - { - return ret; - } - - throw; - } - } - } -} \ No newline at end of file diff --git a/samples/video-translation/csharp/Common/CommonLib/CommandParser/ExitCode.cs b/samples/video-translation/csharp/Common/CommonLib/CommandParser/ExitCode.cs deleted file mode 100644 index 8f98ca91c..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommandParser/ExitCode.cs +++ /dev/null @@ -1,19 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.CommandParser; - -public sealed class ExitCode -{ - public const int NoError = 0; - - public const int InvalidArgument = -1; - - public const int GenericError = 999; - - private ExitCode() - { - } -} \ No newline at end of file diff --git a/samples/video-translation/csharp/Common/CommonLib/CommandParser/InOutType.cs b/samples/video-translation/csharp/Common/CommonLib/CommandParser/InOutType.cs deleted file mode 100644 index 59efc8a3e..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommandParser/InOutType.cs +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.CommandParser; - -public enum InOutType -{ - Unknown, - - In, - - Out, - - InOut, -} diff --git a/samples/video-translation/csharp/Common/CommonLib/CommonConst.cs b/samples/video-translation/csharp/Common/CommonLib/CommonConst.cs deleted file mode 100644 index 525fce4c1..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommonConst.cs +++ /dev/null @@ -1,55 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib; - -using System; -using System.Collections.Generic; - -public static class CommonConst -{ - public static class VideoTranslation - { - public static class ApiVersions - { - public const string PublicPreviewApiVersion20240520Preview = "2024-05-20-preview"; - } - } - - public static class Http - { - public static readonly TimeSpan OperationQueryDuration = TimeSpan.FromSeconds(3); - - public static class Headers - { - public const string OperationId = "Operation-Id"; - public const string OperationLocation = "Operation-Location"; - - public readonly static IEnumerable OperationHeaders = new[] - { - OperationId, - OperationLocation, - }; - } - - public static class MimeType - { - public const string HttpAudioBasic = "audio/basic"; - public const string HttpAudioSilk = "audio/SILK"; - public const string HttpAudioSilk24K = "audio/SILK; samplerate=24000"; - public const string HttpAudioXwave = "audio/x-wav"; - public const string TextXml = "text/xml"; - public const string Text = "text/plain"; - public const string TextJson = "application/json"; - public const string HttpSsmlXml = "application/ssml+xml"; - public const string HttpAudioMpeg = "audio/mpeg"; - public const string OpusAudio16K = "audio/ogg; codecs=opus; rate=16000"; - public const string OpusAudio24K = "audio/ogg; codecs=opus; rate=24000"; - public const string OpusAudio48K = "audio/ogg; codecs=opus; rate=48000"; - public const string Zip = "application/zip"; - public const string AudioMp3 = "audio/mpeg3"; - } - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/CommonLib.csproj b/samples/video-translation/csharp/Common/CommonLib/CommonLib.csproj deleted file mode 100644 index 0aa211b67..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CommonLib.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net7.0 - Microsoft.SpeechServices.CommonLib - Microsoft.SpeechServices.CommonLib - - - - - - - - - - - - - - - - - diff --git a/samples/video-translation/csharp/Common/CommonLib/CustomContractResolver.cs b/samples/video-translation/csharp/Common/CommonLib/CustomContractResolver.cs deleted file mode 100644 index 3885709e8..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/CustomContractResolver.cs +++ /dev/null @@ -1,143 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Microsoft.SpeechServices.CommonLib.Enums; -using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using Newtonsoft.Json.Serialization; - -public class CustomContractResolver : CamelCasePropertyNamesContractResolver -{ - public static readonly CustomContractResolver ReaderContractResolver = new CustomContractResolver(); - public static readonly CustomContractResolver WriterContractResolver = new CustomContractResolver(); - - public static JsonSerializerSettings WriterSettings { get; } = new JsonSerializerSettings - { - ContractResolver = WriterContractResolver, - ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, - Converters = new List { new StringEnumConverter() { AllowIntegerValues = false } }, - DateFormatString = "yyyy-MM-ddTHH\\:mm\\:ss.fffZ", - NullValueHandling = NullValueHandling.Ignore, - Formatting = Formatting.Indented, - ReferenceLoopHandling = ReferenceLoopHandling.Ignore - }; - - public static JsonSerializerSettings ReaderSettings { get; } = new JsonSerializerSettings - { - ContractResolver = ReaderContractResolver, - ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor, - Converters = new List { new StringEnumConverter() { AllowIntegerValues = true } }, - Formatting = Formatting.Indented - }; - - public static string GetResolvedPropertyName(PropertyInfo property) - { - ArgumentNullException.ThrowIfNull(property); - - string propertyName; - var jsonAttribute = property.GetCustomAttributes(typeof(JsonPropertyAttribute)).Cast().FirstOrDefault(); - if (jsonAttribute != null && !string.IsNullOrWhiteSpace(jsonAttribute.PropertyName)) - { - propertyName = jsonAttribute.PropertyName; - } - else - { - propertyName = ReaderContractResolver.GetResolvedPropertyName(property.Name); - } - - return propertyName; - } - - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var property = base.CreateProperty(member, memberSerialization); - - if (!property.Writable) - { - var propertyInfo = member as PropertyInfo; - if (propertyInfo != null) - { - property.Writable = propertyInfo.CanWrite; - } - } - - const string createdDateTime = "CreatedDateTime"; - const string lastActionDateTime = "LastActionDateTime"; - const string status = "Status"; - const string timeToLive = "TimeToLive"; - const string duration = "Duration"; - const string customProperties = "CustomProperties"; - - if (property.PropertyType == typeof(DateTime) && property.PropertyName == this.ResolvePropertyName(createdDateTime)) - { - property.ShouldSerialize = - instance => - { - var value = (DateTime)instance.GetType().GetProperty(createdDateTime).GetValue(instance); - return value != default(DateTime); - }; - } - else if (property.PropertyType == typeof(DateTime) && property.PropertyName == this.ResolvePropertyName(lastActionDateTime)) - { - property.ShouldSerialize = - instance => - { - var value = (DateTime)instance.GetType().GetProperty(lastActionDateTime).GetValue(instance); - return value != default(DateTime); - }; - } - else if (property.PropertyType == typeof(OneApiState) && property.PropertyName == this.ResolvePropertyName(status)) - { - property.ShouldSerialize = - instance => - { - var value = (OneApiState)instance.GetType().GetProperty(status).GetValue(instance); - return value != default(OneApiState); - }; - } - else if (property.PropertyType == typeof(TimeSpan) && property.PropertyName == this.ResolvePropertyName(timeToLive)) - { - property.ShouldSerialize = - instance => - { - var value = (TimeSpan)instance.GetType().GetProperty(timeToLive).GetValue(instance); - return value != TimeSpan.Zero; - }; - } - else if (property.PropertyType == typeof(TimeSpan) && property.PropertyName == this.ResolvePropertyName(duration)) - { - property.ShouldSerialize = - instance => - { - var value = (TimeSpan)instance.GetType().GetProperty(duration).GetValue(instance); - return value != TimeSpan.Zero; - }; - } - else if (property.PropertyType == typeof(IReadOnlyDictionary) && property.PropertyName == this.ResolvePropertyName(customProperties)) - { - property.ShouldSerialize = - instance => - { - var value = (IReadOnlyDictionary)instance.GetType().GetProperty(customProperties).GetValue(instance); - return value != null && value.Count > 0; - }; - } - - return property; - } - - // do not javascriptify (camel case) dictionary keys. This would e.g. change - // key in artifact properties. - protected override string ResolveDictionaryKey(string dictionaryKey) - { - return dictionaryKey; - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskBrief.cs b/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskBrief.cs deleted file mode 100644 index 89c227ffb..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskBrief.cs +++ /dev/null @@ -1,12 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -using Microsoft.SpeechServices.Cris.Http.DTOs.Public; - -namespace Microsoft.SpeechServices.DataContracts; - -public class VoiceGeneralTaskBrief : StatefulResourceBase -{ -} diff --git a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskInputFileBase.cs b/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskInputFileBase.cs deleted file mode 100644 index 6d36ea60f..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/VoiceGeneralTaskInputFileBase.cs +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VoiceGeneralTask; - -using System; - -public class VoiceGeneralTaskInputFileBase : StatefulResourceBase -{ - public string FileContentSha256 { get; set; } - - public Uri Url { get; set; } - - public long? Version { get; set; } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationFileKind.cs b/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationFileKind.cs deleted file mode 100644 index 00a218558..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationFileKind.cs +++ /dev/null @@ -1,15 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Enums; - -public enum VideoTranslationFileKind -{ - None = 0, - - VideoFile, - - AudioFile, -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationMergeParagraphAudioAlignKind.cs b/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationMergeParagraphAudioAlignKind.cs deleted file mode 100644 index f55d869a2..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationMergeParagraphAudioAlignKind.cs +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Enums; - -using System; - -public enum VideoTranslationMergeParagraphAudioAlignKind -{ - [Obsolete("Do not use directly - used to discover serializer issues.")] - None = 0, - - TruncateIfExceed, - - SpeedUpIfExceed, -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationVoiceKind.cs b/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationVoiceKind.cs deleted file mode 100644 index 730e69a78..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Enums/VideoTranslationVoiceKind.cs +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -using System; - -namespace Microsoft.SpeechServices.Common.Client; - -public enum VideoTranslationVoiceKind -{ - [Obsolete("Do not use directly - used to discover serializer issues.")] - None = 0, - - PlatformVoice, - - PersonalVoice, - - ZeroShot, -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Extensions/EnumExtensions.cs b/samples/video-translation/csharp/Common/CommonLib/Extensions/EnumExtensions.cs deleted file mode 100644 index bed0a4515..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Extensions/EnumExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Extensions; - -using System; -using System.Linq; -using System.Reflection; - -public static class EnumExtensions -{ - public static T GetAttributeOfType(this Enum enumValue) where T : Attribute - { - var type = enumValue.GetType(); - var memInfo = type.GetMember(enumValue.ToString()).First(); - var attributes = memInfo.GetCustomAttributes(false); - return attributes.FirstOrDefault(); - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Extensions/FileNameExtensions.cs b/samples/video-translation/csharp/Common/CommonLib/Extensions/FileNameExtensions.cs deleted file mode 100644 index e76b9998c..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Extensions/FileNameExtensions.cs +++ /dev/null @@ -1,295 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.Common; - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; - -public static class FileNameExtensions -{ - public const char FileExtensionDelimiter = '.'; - - public const string Mp3 = "mp3"; - - public const string Mp4 = "mp4"; - - public const string CloudAudioMetadataFile = "metadata"; - - public const string VideoTranslationDubbingMetricsReferenceYaml = "info.yaml"; - - public const string CloudAudioTsvFile = "tsv"; - - public const string Waveform = "wav"; - - public const string RawWave = "raw"; - - public const string Ogg = "ogg"; - - public const string Text = "txt"; - - public const string Tsv = "tsv"; - - public const string Xml = "xml"; - - public const string Yaml = "yaml"; - - public const string Configuration = "config"; - - public const string CsvFile = "csv"; - - public const string ExcelFile = "xlsx"; - - public const string ZipFile = "zip"; - - public const string HtmlFile = "html"; - - public const string PngFile = "png"; - - public const string JpegFile = "jpeg"; - - public const string JsonFile = "json"; - - public const string Zip7Z = "7z"; - - public const string IniFile = "ini"; - - public const string LgMarkdownFile = "lg"; - - public const string PdfFile = "pdf"; - - public const string PptxFile = "pptx"; - - public const string WaveformRaw = "raw"; - - public const string SubRipFile = "srt"; - - public const string WebVttFile = "vtt"; - - public const string WebmVideoFile = "webm"; - - public const string M4aAudioFile = "m4a"; - - public const string PitchF0File = "if0"; - - public static string EnsureExtensionWithoutDelimiter(this string extension) - { - string extensionWithoutDelimeter = string.Empty; - if (!string.IsNullOrEmpty(extension)) - { - if (extension[0] == FileExtensionDelimiter) - { - extensionWithoutDelimeter = extension.Substring(1); - } - else - { - extensionWithoutDelimeter = extension; - } - } - - return extensionWithoutDelimeter; - } - - public static string EnsureExtensionWithDelimiter(this string extension) - { - string extensionWithDelimiter = extension; - if (!string.IsNullOrEmpty(extension)) - { - if (extension[0] != FileExtensionDelimiter) - { - extensionWithDelimiter = FileExtensionDelimiter + extension; - } - else - { - extensionWithDelimiter = extension; - } - } - - return extensionWithDelimiter; - } - - public static string AppendExtensionName(this string file, string extensionName) - { - extensionName = extensionName ?? string.Empty; - return (string.IsNullOrEmpty(extensionName) || extensionName[0] == FileExtensionDelimiter) ? file + extensionName : file + FileExtensionDelimiter + extensionName; - } - - public static bool IsWithFileExtension(this string file, string extensionName) - { - if (string.IsNullOrEmpty(file)) - { - throw new ArgumentNullException(nameof(file)); - } - - if (string.IsNullOrEmpty(extensionName)) - { - throw new ArgumentNullException(nameof(extensionName)); - } - - if (extensionName[0] != FileExtensionDelimiter) - { - extensionName = FileExtensionDelimiter + extensionName; - } - - return file.EndsWith(extensionName, StringComparison.OrdinalIgnoreCase); - } - - public static bool IsSameFileExtension(this string actualExtension, string expectedExtension) - { - if (string.IsNullOrEmpty(actualExtension)) - { - throw new ArgumentNullException(nameof(actualExtension)); - } - - if (string.IsNullOrEmpty(expectedExtension)) - { - throw new ArgumentNullException(nameof(expectedExtension)); - } - - string actualExtensionWithoutDelimeter = actualExtension; - if (actualExtension[0] == FileExtensionDelimiter) - { - actualExtensionWithoutDelimeter = actualExtension.Substring(1); - } - - string expectedExtensionWithoutDelimeter = expectedExtension; - if (expectedExtension[0] == FileExtensionDelimiter) - { - expectedExtensionWithoutDelimeter = expectedExtension.Substring(1); - } - - bool isSame = true; - if (string.CompareOrdinal(actualExtensionWithoutDelimeter, expectedExtensionWithoutDelimeter) != 0) - { - isSame = false; - } - - return isSame; - } - - public static bool IsSupportedFileExtension(this string actualExtension, IEnumerable supportedExtensions, StringComparison stringComparison = StringComparison.CurrentCulture) - { - ArgumentNullException.ThrowIfNull(actualExtension); - ArgumentNullException.ThrowIfNull(supportedExtensions); - - string actualExtensionWithoutDelimeter = actualExtension.EnsureExtensionWithoutDelimiter(); - var supportedExtensionsWithoutDelimeter = supportedExtensions.Select(extension => extension.EnsureExtensionWithoutDelimiter()); - - return supportedExtensionsWithoutDelimeter.Any(extenstion => actualExtensionWithoutDelimeter.Equals(extenstion, stringComparison)); - } - - public static string CreateSearchPatternWithFileExtension(this string fileExtension) - { - if (string.IsNullOrEmpty(fileExtension)) - { - throw new ArgumentNullException(nameof(fileExtension)); - } - - return "*".AppendExtensionName(fileExtension); - } - - public static string RemoveFilePathExtension(this string filePath) - { - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentNullException(nameof(filePath)); - } - - return Path.Combine(Path.GetDirectoryName(filePath), Path.GetFileNameWithoutExtension(filePath)); - } - - public static string ChangeFilePathExtension(this string filePath, string newFileNameExtension) - { - if (string.IsNullOrEmpty(filePath)) - { - throw new ArgumentNullException(nameof(filePath)); - } - - return Path.GetFileNameWithoutExtension(filePath).AppendExtensionName(newFileNameExtension); - } - - public static bool HasFileExtension(this string fileName) - { - try - { - return !string.IsNullOrWhiteSpace(fileName) && !string.IsNullOrWhiteSpace(fileName.GetFileExtension()); - } - catch (ArgumentException) - { - return false; - } - } - - public static string GetFileExtension(this string fileName, bool withDelimiter = true) - { - if (string.IsNullOrWhiteSpace(fileName)) - { - throw new ArgumentException("The file name is either an empty string, null or whitespace.", nameof(fileName)); - } - - try - { - var fileInfo = new FileInfo(fileName); - - if (!withDelimiter) - { - if (fileInfo.Extension.StartsWith(FileExtensionDelimiter.ToString(), StringComparison.InvariantCultureIgnoreCase)) - { - return fileInfo.Extension.Substring(1); - } - } - - return fileInfo.Extension; - } - catch (ArgumentException) - { - return string.Empty; - } - } - - public static string GetLowerCaseFileNameExtensionWithoutDot(string fileName) - { - if (string.IsNullOrEmpty(fileName)) - { - throw new ArgumentNullException(nameof(fileName)); - } - - var extension = Path.GetExtension(fileName); - if (string.IsNullOrEmpty(extension)) - { - return extension; - } - - extension = extension.TrimStart('.'); -#pragma warning disable CA1308 // Normalize strings to uppercase - return extension.ToLowerInvariant(); -#pragma warning restore CA1308 // Normalize strings to uppercase - } - - public static string GetFileNameExtensionFromCodec(string codec) - { - var fileExtension = FileNameExtensions.Waveform; - if (codec.IndexOf("riff", StringComparison.OrdinalIgnoreCase) >= 0) - { - fileExtension = FileNameExtensions.Waveform; - } - else if (codec.IndexOf("mp3", StringComparison.OrdinalIgnoreCase) >= 0) - { - fileExtension = FileNameExtensions.Mp3; - } - else if (codec.IndexOf("raw", StringComparison.OrdinalIgnoreCase) >= 0) - { - fileExtension = FileNameExtensions.RawWave; - } - else if (codec.IndexOf("json", StringComparison.OrdinalIgnoreCase) >= 0) - { - fileExtension = FileNameExtensions.JsonFile; - } - - return fileExtension; - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Extensions/StringExtensions.cs b/samples/video-translation/csharp/Common/CommonLib/Extensions/StringExtensions.cs deleted file mode 100644 index abe278949..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Extensions/StringExtensions.cs +++ /dev/null @@ -1,54 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Extensions; - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; - -public static class StringExtensions -{ - public static string MaskSasToken(this string str) - { - if (string.IsNullOrWhiteSpace(str)) - { - return str; - } - - var sasRegexPattern = "(?sig=[\\w%]+)"; - var matches = Regex.Matches(str, sasRegexPattern); - foreach (Match match in matches) - { - str = str.Replace(match.Groups["signature"].Value, "SIGMASKED"); - } - - return str; - } - - public static IReadOnlyDictionary ToDictionaryWithDelimeter(this string value) - { - var headers = new Dictionary(); - if (!string.IsNullOrEmpty(value)) - { - var headerPairs = value.Split(new char[] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var headerPair in headerPairs.Where(x => !string.IsNullOrEmpty(x))) - { - var delimeterIndex = headerPair.IndexOf('='); - if (delimeterIndex < 0) - { - throw new InvalidDataException($"Invalid argument format: {value}"); - } - - headers[headerPair.Substring(0, delimeterIndex)] = headerPair.Substring(delimeterIndex + 1); - } - } - - return headers; - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/HttpClientConfigBase.cs b/samples/video-translation/csharp/Common/CommonLib/HttpClientConfigBase.cs deleted file mode 100644 index c15348682..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/HttpClientConfigBase.cs +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Util; - -using Flurl; -using Flurl.Http; -using Microsoft.SpeechServices.CommonLib.Attributes; -using Microsoft.SpeechServices.CommonLib.Extensions; -using System; - -public abstract class HttpClientConfigBase - where TDeploymentEnvironment : Enum -{ - public HttpClientConfigBase(TDeploymentEnvironment environment, string subKey) - { - this.Environment = environment; - this.SubscriptionKey = subKey; - } - - public virtual Uri RootUrl - { - get - { - // Use APIM for public API. - return this.BaseUrl - .AppendPathSegment(RouteBase) - .ToUri(); - } - } - - public virtual string ApiVersion { get; set; } - - public abstract string RouteBase { get; } - - public TDeploymentEnvironment Environment { get; set; } - - public string SubscriptionKey { get; set; } - - public virtual Uri BaseUrl - { - get - { - return this.Environment.GetAttributeOfType()?.GetApimApiBaseUrl(); - } - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Readme.txt b/samples/video-translation/csharp/Common/CommonLib/Readme.txt deleted file mode 100644 index c057f40db..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Readme.txt +++ /dev/null @@ -1,2 +0,0 @@ -Nuget: - 1. Not upgrade Flurl to 4.0 due to 4.0 doesn't support NewtonJson for ReceiveJson. \ No newline at end of file diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/ConsoleHelper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/ConsoleHelper.cs deleted file mode 100644 index 4eb3bc50e..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/ConsoleHelper.cs +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CustomVoice.TtsLib.Util; - -using Microsoft.SpeechServices.CommonLib.Extensions; -using System; -using System.Diagnostics; -using System.IO; - -public static class ConsoleHelper -{ - public static void WriteLineErrorMaskSas(string message) - { - Console.Error.WriteLine(message.MaskSasToken()); - } - - public static void WriteLineErrorMaskSas() - { - Console.Error.WriteLine(); - } - - public static void WriteMaskSas(string message) - { - Console.Write(message.MaskSasToken()); - } - - public static void WriteLineMaskSas() - { - Console.WriteLine(); - } - - public static void WriteLineMaskSas(string message) - { - Console.WriteLine(message.MaskSasToken()); - } - - public static string TempRoot - { - get - { - return Path.Combine(Path.GetPathRoot(Process.GetCurrentProcess().MainModule.FileName), "Temp"); - } - } - - public static string GetTempDir() - { - return Path.Combine(TempRoot, Guid.NewGuid().ToString()); - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/ConsoleMaskSasHelper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/ConsoleMaskSasHelper.cs deleted file mode 100644 index 61cc39b3c..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/ConsoleMaskSasHelper.cs +++ /dev/null @@ -1,24 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Util; - -using Microsoft.SpeechServices.CommonLib.Extensions; -using System; - -public static class ConsoleMaskSasHelper -{ - public static bool ShowSas { get; set; } - - static ConsoleMaskSasHelper() - { - ShowSas = false; - } - - public static void WriteLineMaskSas(string message) - { - Console.WriteLine(ShowSas ? message : message.MaskSasToken()); - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/EnumExtensions.cs b/samples/video-translation/csharp/Common/CommonLib/Util/EnumExtensions.cs deleted file mode 100644 index 0ce93d881..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/EnumExtensions.cs +++ /dev/null @@ -1,58 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Util; - -using System; -using System.Linq; -using System.Runtime.Serialization; - -public static class EnumExtensions -{ - public static string AsString(this TEnum enumValue) - where TEnum : Enum - { - if (typeof(TEnum).GetCustomAttributes(typeof(FlagsAttribute), false).Any()) - { - return enumValue.ToString(); - } - - var enumMemberName = Enum.GetName(typeof(TEnum), enumValue); - - var enumMember = typeof(TEnum).GetMember(enumMemberName).Single(); - var jsonPropertyAttribute = enumMember - .GetCustomAttributes(typeof(DataMemberAttribute), true) - .Cast() - .SingleOrDefault(); - - if (jsonPropertyAttribute != null) - { - return jsonPropertyAttribute.Name; - } - - return enumMemberName; - } - - public static TEnum AsEnumValue(this string value) - { - return value.AsEnumValue(false); - } - - public static TEnum AsEnumValue(this string value, bool ignoreCase) - { - var enumMembers = typeof(TEnum).GetMembers(); - var membersAndAttributes = enumMembers - .Select(m => (member: m, attribute: m.GetCustomAttributes(typeof(DataMemberAttribute), true).Cast().SingleOrDefault())) - .Where(m => m.attribute != null) - .Where(m => m.attribute.Name == value); - - if (membersAndAttributes.Any()) - { - value = membersAndAttributes.Single().member.Name; - } - - return (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase); - } -} \ No newline at end of file diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/JsonHelper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/JsonHelper.cs deleted file mode 100644 index 90894ae3c..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/JsonHelper.cs +++ /dev/null @@ -1,70 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CustomVoice; - -using System; -using System.Collections.Generic; -using System.Linq; -using Microsoft.SpeechServices.CommonLib; -using Microsoft.SpeechServices.CustomVoice.TtsLib.TtsUtil; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -public static class JsonHelper -{ - public static (bool success, string error, IEnumerable texts) ExtractElementsByJSONPath(string jsonContent, string jsonPath) - { - var texts = new List(); - if (string.IsNullOrEmpty(jsonContent)) - { - return (true, null, texts); - } - - try - { - JObject o = JObject.Parse(jsonContent); - if (o == null) - { - return (false, "Empty JObject returned when parse content with JObject.", null); - } - - var tokens = o.SelectTokens(jsonPath); - if (tokens?.Any() ?? false) - { - tokens.Where(x => x != null).ToList().ForEach(x => texts.Add(x.ToString())); - } - } - catch (JsonReaderException e) - { - return (false, e.Message, null); - } - - return (true, null, texts); - } - - public static (bool success, string error, T result) TryParse(string jsonString, JsonSerializerSettings readerSettings) - { - ArgumentNullException.ThrowIfNull(readerSettings); - - if (string.IsNullOrEmpty(jsonString)) - { - return (false, "Json input should not be empty.", default(T)); - } - - T result = default(T); - (var success, var error) = ExceptionHelper.HasRunWithoutException(() => - { - result = JsonConvert.DeserializeObject(jsonString, readerSettings); - }); - - return (success, error, result); - } - - public static (bool success, string error, T result) TryParse(string jsonString) - { - return TryParse(jsonString, CustomContractResolver.ReaderSettings); - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/Sha256Helper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/Sha256Helper.cs deleted file mode 100644 index 72a9d18e1..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/Sha256Helper.cs +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Util; - -using Microsoft.SpeechServices.Common; -using System; -using System.Globalization; -using System.IO; -using System.Security.Cryptography; -using System.Text; - -public static class Sha256Helper -{ - public static string GetSha256FromFile(string filename) - { - if (string.IsNullOrEmpty(filename)) - { - throw new ArgumentNullException(nameof(filename)); - } - - if (!File.Exists(filename)) - { - throw new FileNotFoundException(filename); - } - - using (var md5Hash = SHA256.Create()) - using (FileStream stream = File.OpenRead(filename)) - { - byte[] data = md5Hash.ComputeHash(stream); - var sb = new StringBuilder(); - - for (int i = 0; i < data.Length; i++) - { - sb.Append(data[i].ToString("x2", CultureInfo.InvariantCulture)); - } - - return sb.ToString(); - } - } - - public static string GetSha256WithExtensionFromFile(string filename) - { - return $"{GetSha256FromFile(filename).AppendExtensionName(Path.GetExtension(filename))}"; - } - - public static string GetSha256FromString(string value) - { - value = value ?? string.Empty; - using (var md5Hash = SHA256.Create()) - { - byte[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(value)); - - StringBuilder sb = new StringBuilder(); - - for (int i = 0; i < data.Length; i++) - { - sb.Append(data[i].ToString("x2", CultureInfo.InvariantCulture)); - } - - return sb.ToString(); - } - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/StringFormatHelper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/StringFormatHelper.cs deleted file mode 100644 index abaaf7b42..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/StringFormatHelper.cs +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CustomVoice.TtsLib.Util; - -using System; -using System.Globalization; - -public static class StringFormatHelper -{ - public static string ToIdSuffix(this DateTime timestamp) - { - return timestamp.ToString(@"yyMMddhhmmss", CultureInfo.InvariantCulture); - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/TaskNameHelper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/TaskNameHelper.cs deleted file mode 100644 index c654d51cd..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/TaskNameHelper.cs +++ /dev/null @@ -1,61 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CommonLib.Util; - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -public static class TaskNameHelper -{ - public const int NameMaxCharLength = 256; - public const string IncompleteFileNamePrefix = "..."; - - public static string BuildAutoGeneratedFileName(IEnumerable fileNames) - { - ArgumentNullException.ThrowIfNull(fileNames); - - var fileName = string.Empty; - if (!fileNames.Any()) - { - fileName = "No file selected."; - } - else if (fileNames.Count() == 1) - { - fileName = $"{fileNames.First()}"; - } - else - { - fileName = TrimFileNameToDisplayText( - $"{fileNames.Count()} files: {string.Join(",", fileNames)}", - NameMaxCharLength); - } - - return fileName; - } - - public static string TrimFileNameToDisplayText(string fullFileName, int maxFileNameCharCount) - { - if (string.IsNullOrEmpty(fullFileName)) - { - return fullFileName; - } - - var sb = new StringBuilder(); - if (fullFileName.Length > maxFileNameCharCount && fullFileName.Length > IncompleteFileNamePrefix.Length) - { - sb.Append(fullFileName.Substring(fullFileName.Length - IncompleteFileNamePrefix.Length)); - sb.Append(IncompleteFileNamePrefix); - } - else - { - sb.Append(fullFileName); - } - - return sb.ToString(); - } -} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/UriHelper.cs b/samples/video-translation/csharp/Common/CommonLib/Util/UriHelper.cs deleted file mode 100644 index 3bfb4b7a1..000000000 --- a/samples/video-translation/csharp/Common/CommonLib/Util/UriHelper.cs +++ /dev/null @@ -1,53 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.CustomVoice.TtsLib.Util; - -using System; -using System.Linq; - -public static class UriHelper -{ - public static string GetFileName(Uri url) - { - if (string.IsNullOrWhiteSpace(url?.OriginalString)) - { - throw new ArgumentNullException(nameof(url)); - } - - var videoFileName = url.Segments.Last(); - videoFileName = Uri.UnescapeDataString(videoFileName); - return videoFileName; - } - - public static string AppendOptionalQuery(this string query, string name, string value) - { - if (string.IsNullOrEmpty(value)) - { - return query; - } - - var item = $"{name}={Uri.EscapeDataString(value)}"; - return string.IsNullOrEmpty(query) ? item : $"{query}&{item}"; - } - - // query include ? - public static Uri SetQuery(Uri uri, string query) - { - if (uri == null) - { - throw new ArgumentNullException(nameof(uri)); - } - - var uriString = uri.ToString(); - var index = uriString.IndexOf("?"); - if (index < 0) - { - return uri; - } - - return new Uri($"{uriString.Substring(0, index)}{query}"); - } -} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.Common/Enum/DeploymentEnvironment.cs b/samples/video-translation/csharp/Common/VideoTranslationLib.Common/Enum/DeploymentEnvironment.cs deleted file mode 100644 index a52619777..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.Common/Enum/DeploymentEnvironment.cs +++ /dev/null @@ -1,22 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslationLib.Enums; - -using Microsoft.SpeechServices.CommonLib.Attributes; -using System; -using System.Runtime.Serialization; - -[DataContract] -public enum DeploymentEnvironment -{ - [EnumMember] - Default, - - [EnumMember] - [DeploymentEnvironment( - regionIdentifier: "eastus")] - ProductionEUS, -} \ No newline at end of file diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationConstant.cs b/samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationConstant.cs deleted file mode 100644 index 9b67dc350..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationConstant.cs +++ /dev/null @@ -1,13 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslation; - -using System; - -public static class VideoTranslationConstant -{ - public readonly static TimeSpan UploadVideoOrAudioFileTimeout = TimeSpan.FromMinutes(10); -} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/ConsoleAppHelper.cs b/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/ConsoleAppHelper.cs deleted file mode 100644 index c7b2208dc..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/ConsoleAppHelper.cs +++ /dev/null @@ -1,67 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslationLib.PublicPreview.Base; - -using Microsoft.SpeechServices.CommonLib; -using Microsoft.SpeechServices.CommonLib.Util; -using Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; -using Microsoft.SpeechServices.CustomVoice.TtsLib.Util; -using Microsoft.VisualBasic; -using Newtonsoft.Json; -using System; -using System.Globalization; -using System.Threading.Tasks; -using VideoTranslationPublicPreviewLib.HttpClient; - -public static class ConsoleAppHelper -{ - public static async Task CreateTranslationAsync( - TranslationClient translationClient, - string translationId, - CultureInfo sourceLocale, - CultureInfo targetLocale, - VoiceKind voiceKind, - Uri videoFileUrl, - int? speakerCount) - where TDeploymentEnvironment : Enum - where TIteration : Iteration - where TIterationInput : IterationInput - { - ArgumentNullException.ThrowIfNull(translationClient); - if (string.IsNullOrWhiteSpace(videoFileUrl?.OriginalString)) - { - throw new ArgumentNullException(nameof(videoFileUrl)); - } - - var fileName = UriHelper.GetFileName(videoFileUrl); - var translation = new Translation() - { - Id = translationId, - DisplayName = fileName, - Description = $"Translation {fileName} from {sourceLocale} to {targetLocale} with {voiceKind.AsString()}", - Input = new TranslationInput() - { - SourceLocale = sourceLocale, - TargetLocale = targetLocale, - SpeakerCount = speakerCount, - VoiceKind = voiceKind, - VideoFileUrl = videoFileUrl, - }, - }; - - var operationId = Guid.NewGuid().ToString(); - (translation, var headers) = await translationClient.CreateTranslationAsync( - translation: translation, - operationId: operationId).ConfigureAwait(false); - - Console.WriteLine(); - Console.WriteLine("Created translation:"); - Console.WriteLine(JsonConvert.SerializeObject( - translation, - Formatting.Indented, - CustomContractResolver.WriterSettings)); - } -} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/VoiceKindExtensions.cs b/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/VoiceKindExtensions.cs deleted file mode 100644 index 7d25feb72..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/VoiceKindExtensions.cs +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; - -using Microsoft.SpeechServices.Common.Client; - -public static class VoiceKindExtensions -{ - public static VideoTranslationVoiceKind AsCoreEngineEnum(this VoiceKind voiceKind) - { - return voiceKind switch - { - VoiceKind.PlatformVoice => VideoTranslationVoiceKind.PlatformVoice, - VoiceKind.PersonalVoice => VideoTranslationVoiceKind.PersonalVoice, - _ => VideoTranslationVoiceKind.PlatformVoice, - }; - } -} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs b/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs deleted file mode 100644 index 487a42133..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; - -using Newtonsoft.Json; - -public class Iteration : StatefulResourceBase - where TIterationInput : IterationInput -{ - public TIterationInput Input { get; set; } - - public IterationResult Result { get; set; } - - public string? FailureReason { get; set; } - - // This is different from the content editin concept in billing, billing is based on first iteration or not. - [JsonIgnore] - public bool IsContentEditing - { - get - { - return this.Input?.WebvttFile?.HasValue() ?? false; - } - } -} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationLib.PublicPreview.csproj b/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationLib.PublicPreview.csproj deleted file mode 100644 index 8f8fbf67d..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationLib.PublicPreview.csproj +++ /dev/null @@ -1,13 +0,0 @@ - - - - net7.0 - Microsoft.SpeechServices.VideoTranslationLib.PublicPreview.Base - Microsoft.SpeechServices.VideoTranslationLib.PublicPreview.Base - - - - - - - diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationPublicPreviewHttpClientConfig.cs b/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationPublicPreviewHttpClientConfig.cs deleted file mode 100644 index f6941ef3b..000000000 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/VideoTranslationPublicPreviewHttpClientConfig.cs +++ /dev/null @@ -1,42 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslation; - -using Flurl; -using Microsoft.SpeechServices.CommonLib.Attributes; -using Microsoft.SpeechServices.CommonLib.Extensions; -using Microsoft.SpeechServices.CommonLib.Util; -using System; - -public class VideoTranslationPublicPreviewHttpClientConfig : - HttpClientConfigBase - where TDeploymentEnvironment : Enum -{ - public VideoTranslationPublicPreviewHttpClientConfig(TDeploymentEnvironment environment, string subKey) - : base(environment, subKey) - { - } - - public override string RouteBase => "videotranslation"; - - public override Uri RootUrl - { - get - { - return this.BaseUrl - .AppendPathSegment(RouteBase) - .ToUri(); - } - } - - public override Uri BaseUrl - { - get - { - return this.Environment.GetAttributeOfType()?.GetApimApiBaseUrl(); - } - } -} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationLib.Common.csproj b/samples/video-translation/csharp/CommonLib.Public/CommonLib.Public.csproj similarity index 56% rename from samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationLib.Common.csproj rename to samples/video-translation/csharp/CommonLib.Public/CommonLib.Public.csproj index c418d57fa..2328ca0be 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.Common/VideoTranslationLib.Common.csproj +++ b/samples/video-translation/csharp/CommonLib.Public/CommonLib.Public.csproj @@ -1,19 +1,17 @@ - net7.0 - Microsoft.SpeechServices.$(MSBuildProjectName) - Microsoft.SpeechServices.VideoTranslation + net8.0 + Microsoft.SpeechServices.CommonLib.Public + Microsoft.SpeechServices.CommonLib.Public + - - - diff --git a/samples/video-translation/csharp/CommonLib.Public/CommonPublicConst.cs b/samples/video-translation/csharp/CommonLib.Public/CommonPublicConst.cs new file mode 100644 index 000000000..f7c43d51f --- /dev/null +++ b/samples/video-translation/csharp/CommonLib.Public/CommonPublicConst.cs @@ -0,0 +1,77 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.CommonLib; + +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; + +public static class CommonPublicConst +{ + public static class Json + { + // Default json serializer will serialize enum to number, which will cause API parse DTO failure: + // "Error converting value 0 to type 'Microsoft.SpeechServices.Common.Client.OneApiState'. Path 'Status', line 1, position 56." + public static JsonSerializerSettings WriterSettings { get; } = new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Converters = new List { new StringEnumConverter() { AllowIntegerValues = false } }, + DateFormatString = "yyyy-MM-ddTHH\\:mm\\:ss.fffZ", + NullValueHandling = NullValueHandling.Ignore, + Formatting = Formatting.Indented, + }; + + public static JsonSerializerSettings ReaderSettings { get; } = new JsonSerializerSettings + { + ContractResolver = new CamelCasePropertyNamesContractResolver(), + Converters = new List { new StringEnumConverter() { AllowIntegerValues = true } }, + Formatting = Formatting.Indented + }; + } + + public static class ExistCodes + { + public const int NoError = 0; + public const int GenericError = -1; + } + + public static class ApiVersions + { + public const string ApiVersion30beta1 = "v3.0-beta1"; + public const string ApiVersion20230401Preview = "2023-04-01-preview"; + public const string ApiVersion20240520Preview = "2024-05-20-preview"; + public const string ApiVersion20230701Preview = "2023-07-01-preview"; + } + + public static class Http + { + public readonly static TimeSpan UploadFileTimeout = TimeSpan.FromMinutes(10); + + public static readonly TimeSpan OperationQueryDuration = TimeSpan.FromSeconds(3); + + public static readonly TimeSpan LongRunOperationTaskExpiredDuration = TimeSpan.FromHours(3); + + public static class ParameterNames + { + public const string ApiVersion = "api-version"; + } + + public static class Headers + { + public const string SubscriptionKey = "Ocp-Apim-Subscription-Key"; + public const string OperationId = "Operation-Id"; + public const string OperationLocation = "Operation-Location"; + + public readonly static IEnumerable OperationHeaders = new[] + { + OperationId, + OperationLocation, + }; + } + } +} diff --git a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/PaginatedResources.cs b/samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/PaginatedResources.cs similarity index 100% rename from samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/PaginatedResources.cs rename to samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/PaginatedResources.cs diff --git a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/ResponseBase.cs b/samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/ResponseBase.cs similarity index 100% rename from samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/ResponseBase.cs rename to samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/ResponseBase.cs diff --git a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/StatefulResourceBase.cs b/samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/StatefulResourceBase.cs similarity index 81% rename from samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/StatefulResourceBase.cs rename to samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/StatefulResourceBase.cs index 58f54eef6..34130dc21 100644 --- a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/StatefulResourceBase.cs +++ b/samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/StatefulResourceBase.cs @@ -6,8 +6,7 @@ namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public; using System; -using Microsoft.SpeechServices.Common.Client; -using Microsoft.SpeechServices.CommonLib.Enums; +using Microsoft.SpeechServices.CommonLib.Public.Enums; public abstract class StatefulResourceBase : StatelessResourceBase { diff --git a/samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/StatelessResourceBase.cs b/samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/StatelessResourceBase.cs similarity index 100% rename from samples/video-translation/csharp/Common/CommonLib/DataContracts/DTOs/Public/StatelessResourceBase.cs rename to samples/video-translation/csharp/CommonLib.Public/DataContracts/DTOs/Public/StatelessResourceBase.cs diff --git a/samples/video-translation/csharp/Common/CommonLib/Enums/OneApiState.cs b/samples/video-translation/csharp/CommonLib.Public/Enums/OneApiState.cs similarity index 87% rename from samples/video-translation/csharp/Common/CommonLib/Enums/OneApiState.cs rename to samples/video-translation/csharp/CommonLib.Public/Enums/OneApiState.cs index f266ebd9e..2491bdc11 100644 --- a/samples/video-translation/csharp/Common/CommonLib/Enums/OneApiState.cs +++ b/samples/video-translation/csharp/CommonLib.Public/Enums/OneApiState.cs @@ -3,11 +3,11 @@ // Licensed under the MIT license. See LICENSE.md file in the project root for full license information. // +namespace Microsoft.SpeechServices.CommonLib.Public.Enums; + using System; using System.Runtime.Serialization; -namespace Microsoft.SpeechServices.CommonLib.Enums; - [DataContract] public enum OneApiState { diff --git a/samples/video-translation/csharp/CommonLib.Public/HttpClient/ApimApiRegionConfig.cs b/samples/video-translation/csharp/CommonLib.Public/HttpClient/ApimApiRegionConfig.cs new file mode 100644 index 000000000..15355ea9c --- /dev/null +++ b/samples/video-translation/csharp/CommonLib.Public/HttpClient/ApimApiRegionConfig.cs @@ -0,0 +1,23 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.CommonLib.Public.Interface; + +using System; + +public class ApimApiRegionConfig : IRegionConfig +{ + public ApimApiRegionConfig(string regionIdentifier) + { + ArgumentNullException.ThrowIfNull(regionIdentifier); + this.RegionIdentifier = regionIdentifier; + } + + public string RegionIdentifier { get; private set; } + + public Uri EndpointUrl => new Uri($"https://{HostName}"); + + private string HostName => $"{this.RegionIdentifier}.api.cognitive.microsoft.com"; +} diff --git a/samples/video-translation/csharp/Common/CommonLib/HttpClientBase.cs b/samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientBase.cs similarity index 65% rename from samples/video-translation/csharp/Common/CommonLib/HttpClientBase.cs rename to samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientBase.cs index f14f6463a..9ae9eedcd 100644 --- a/samples/video-translation/csharp/Common/CommonLib/HttpClientBase.cs +++ b/samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientBase.cs @@ -8,7 +8,8 @@ namespace Microsoft.SpeechServices.CommonLib.Util; using Flurl; using Flurl.Http; using Flurl.Http.Configuration; -using Microsoft.SpeechServices.CommonLib.Enums; +using Microsoft.SpeechServices.CommonLib.Public.Enums; +using Microsoft.SpeechServices.CommonLib.Public.Interface; using Microsoft.SpeechServices.Cris.Http.DTOs.Public; using Microsoft.SpeechServices.CustomVoice.TtsLib.TtsUtil; using Newtonsoft.Json; @@ -20,18 +21,21 @@ namespace Microsoft.SpeechServices.CommonLib.Util; using System.Net; using System.Threading.Tasks; -public abstract class HttpClientBase - where TDeploymentEnvironment : Enum +public abstract class HttpClientBase { - public HttpClientBase(HttpClientConfigBase config) + public HttpClientBase(HttpClientConfigBase config) { this.Config = config; } - protected HttpClientConfigBase Config { get; set; } + protected HttpClientConfigBase Config { get; set; } public abstract string ControllerName { get; } + public IAppLogger Logger { get; set; } + + public virtual bool IsVersionInSegment => false; + public async Task DeleteByIdAsync( string id, IReadOnlyDictionary queryParams = null) @@ -88,13 +92,33 @@ protected async Task QueryByIdAsync( }).ConfigureAwait(false); } + protected IFlurlRequest BuildBackendPathVersionRequestBase( + IReadOnlyDictionary additionalHeaders = null) + { + var url = this.Config.RootUrl + .AppendPathSegment(this.ControllerName) + .WithHeader(CommonPublicConst.Http.Headers.SubscriptionKey, this.Config.SubscriptionKey); + if (additionalHeaders != null) + { + foreach (var additionalHeader in additionalHeaders) + { + url.WithHeader(additionalHeader.Key, additionalHeader.Value); + } + } + + // Default json serializer will serialize enum to number, which will cause API parse DTO failure: + // "Error converting value 0 to type 'Microsoft.SpeechServices.Common.Client.OneApiState'. Path 'Status', line 1, position 56." + url.Settings.JsonSerializer = new NewtonsoftJsonSerializer(CommonPublicConst.Json.WriterSettings); + + return url; + } + protected IFlurlRequest BuildRequestBase( IReadOnlyDictionary additionalHeaders = null) { var url = this.Config.RootUrl .AppendPathSegment(this.ControllerName) - .SetQueryParam("api-version", this.Config.ApiVersion) - .WithHeader("Ocp-Apim-Subscription-Key", this.Config.SubscriptionKey); + .WithHeader(CommonPublicConst.Http.Headers.SubscriptionKey, this.Config.SubscriptionKey); if (additionalHeaders != null) { foreach (var additionalHeader in additionalHeaders) @@ -105,7 +129,7 @@ protected IFlurlRequest BuildRequestBase( // Default json serializer will serialize enum to number, which will cause API parse DTO failure: // "Error converting value 0 to type 'Microsoft.SpeechServices.Common.Client.OneApiState'. Path 'Status', line 1, position 56." - url.Settings.JsonSerializer = new NewtonsoftJsonSerializer(CustomContractResolver.WriterSettings); + url.Settings.JsonSerializer = new NewtonsoftJsonSerializer(CommonPublicConst.Json.WriterSettings); return url; } @@ -121,7 +145,7 @@ public async Task QueryTaskByIdUntilTerminatedAsync( OneApiState? state = null; var firstTimePrinted = false; - while (DateTime.Now - startTime < (timeout ?? TimeSpan.FromHours(3))) + while (DateTime.Now - startTime < (timeout ?? CommonPublicConst.Http.LongRunOperationTaskExpiredDuration)) { var translation = await this.QueryByIdAsync(id, additionalHeaders).ConfigureAwait(false); if (translation == null) @@ -134,23 +158,23 @@ public async Task QueryTaskByIdUntilTerminatedAsync( { runPrinted = true; firstTimePrinted = true; - ConsoleMaskSasHelper.WriteLineMaskSas(JsonConvert.SerializeObject( + this.Logger?.LogLine(JsonConvert.SerializeObject( translation, Formatting.Indented, - CustomContractResolver.WriterSettings)); + CommonPublicConst.Json.WriterSettings)); } if (new[] { OneApiState.Failed, OneApiState.Succeeded }.Contains(translation.Status)) { - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine($"Task completed with state: {translation.Status.AsString()}"); + this.Logger?.LogLine(); + this.Logger?.LogLine(); + this.Logger?.LogLine($"Task completed with state: {translation.Status}"); if (!runPrinted) { - ConsoleMaskSasHelper.WriteLineMaskSas(JsonConvert.SerializeObject( + this.Logger?.LogLine(JsonConvert.SerializeObject( translation, Formatting.Indented, - CustomContractResolver.WriterSettings)); + CommonPublicConst.Json.WriterSettings)); } return translation; @@ -160,9 +184,9 @@ public async Task QueryTaskByIdUntilTerminatedAsync( await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(false); if (state == null || state != translation.Status) { - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine($"Task {translation.Status.AsString()}:"); + this.Logger?.LogLine(); + this.Logger?.LogLine(); + this.Logger?.LogLine($"Task {translation.Status}:"); state = translation.Status; } else @@ -172,9 +196,9 @@ public async Task QueryTaskByIdUntilTerminatedAsync( } } - Console.WriteLine(); - Console.WriteLine(); - Console.WriteLine($"Task run timeout after {(DateTime.Now - startTime).TotalMinutes.ToString("0.00", CultureInfo.InvariantCulture)} mins"); + this.Logger?.LogLine(); + this.Logger?.LogLine(); + this.Logger?.LogLine($"Task run timeout after {(DateTime.Now - startTime).TotalMinutes.ToString("0.00", CultureInfo.InvariantCulture)} mins"); return null; } @@ -191,32 +215,32 @@ public async Task RequestWithRetryAsync(Func(IsTransientError) .WaitAndRetryAsync(5, retryAttempt => { var nextAttemptIn = TimeSpan.FromSeconds(5 * Math.Pow(2, retryAttempt)); - Console.WriteLine($"Retry attempt {retryAttempt} to make request. Next try on {nextAttemptIn.TotalSeconds} seconds."); + this.Logger?.LogLine($"Retry attempt {retryAttempt} to make request. Next try on {nextAttemptIn.TotalSeconds} seconds."); return nextAttemptIn; }); return retryPolicy; } - protected static bool IsTransientError(FlurlHttpException exception) + protected bool IsTransientError(FlurlHttpException exception) { int[] httpStatusCodesWorthRetrying = { - (int)HttpStatusCode.RequestTimeout, // 408 - (int)HttpStatusCode.BadGateway, // 502 - (int)HttpStatusCode.ServiceUnavailable, // 503 - (int)HttpStatusCode.GatewayTimeout, // 504 - (int)HttpStatusCode.TooManyRequests, // 429 - }; - - Console.WriteLine($"Flurl exception status code: {exception.StatusCode}"); + (int)HttpStatusCode.RequestTimeout, // 408 + (int)HttpStatusCode.BadGateway, // 502 + (int)HttpStatusCode.ServiceUnavailable, // 503 + (int)HttpStatusCode.GatewayTimeout, // 504 + (int)HttpStatusCode.TooManyRequests, // 429 + }; + + this.Logger?.LogLine($"Flurl exception status code: {exception.StatusCode}"); return exception.StatusCode.HasValue && httpStatusCodesWorthRetrying.Contains(exception.StatusCode.Value); } } diff --git a/samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientConfigBase.cs b/samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientConfigBase.cs new file mode 100644 index 000000000..7a429615e --- /dev/null +++ b/samples/video-translation/csharp/CommonLib.Public/HttpClient/HttpClientConfigBase.cs @@ -0,0 +1,52 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.CommonLib.Util; + +using Flurl; +using Flurl.Http; +using Microsoft.SpeechServices.CommonLib.Public.Interface; +using System; + +public abstract class HttpClientConfigBase +{ + public HttpClientConfigBase(IRegionConfig regionConfig, string subKey) + { + ArgumentNullException.ThrowIfNull(regionConfig); + this.RegionConfig = regionConfig; + this.SubscriptionKey = subKey; + } + + public virtual Uri RootUrl + { + get + { + // Use APIM for public API. + var url = this.RegionConfig.EndpointUrl + .AppendPathSegment(RouteBase); + + if (this.IsApiVersionInUrlSegment) + { + url = url.AppendPathSegment(this.ApiVersion); + } + else + { + url = url.SetQueryParam(CommonPublicConst.Http.ParameterNames.ApiVersion, this.ApiVersion); + } + + return url.ToUri(); + } + } + + public virtual bool IsApiVersionInUrlSegment => false; + + public virtual string ApiVersion { get; set; } + + public abstract string RouteBase { get; } + + public IRegionConfig RegionConfig { get; set; } + + public string SubscriptionKey { get; set; } +} diff --git a/samples/video-translation/csharp/CommonLib.Public/Interface/IAppLogger.cs b/samples/video-translation/csharp/CommonLib.Public/Interface/IAppLogger.cs new file mode 100644 index 000000000..595bf60b3 --- /dev/null +++ b/samples/video-translation/csharp/CommonLib.Public/Interface/IAppLogger.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.CommonLib.Public.Interface; + +public interface IAppLogger +{ + public void LogLine(); + + public void LogLine(string message); + + public void Log(string message); +} diff --git a/samples/video-translation/csharp/CommonLib.Public/Interface/IRegionConfig.cs b/samples/video-translation/csharp/CommonLib.Public/Interface/IRegionConfig.cs new file mode 100644 index 000000000..9eb202755 --- /dev/null +++ b/samples/video-translation/csharp/CommonLib.Public/Interface/IRegionConfig.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.CommonLib.Public.Interface; + +using System; + +public interface IRegionConfig +{ + public string RegionIdentifier { get; } + + public Uri EndpointUrl { get; } +} diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/CommonHelper.cs b/samples/video-translation/csharp/CommonLib.Public/Util/CommonHelper.cs similarity index 83% rename from samples/video-translation/csharp/Common/CommonLib/Util/CommonHelper.cs rename to samples/video-translation/csharp/CommonLib.Public/Util/CommonHelper.cs index 47de5b996..dc670277c 100644 --- a/samples/video-translation/csharp/Common/CommonLib/Util/CommonHelper.cs +++ b/samples/video-translation/csharp/CommonLib.Public/Util/CommonHelper.cs @@ -11,8 +11,41 @@ namespace Microsoft.SpeechServices.CommonLib.TtsUtil; using System.IO; using System.Text; -public static partial class CommonHelper +public static class CommonHelper { + public static void CopyDirectory(string sourceDir, string destinationDir, bool recursive) + { + // Get information about the source directory + var dir = new DirectoryInfo(sourceDir); + + // Check if the source directory exists + if (!dir.Exists) + throw new DirectoryNotFoundException($"Source directory not found: {dir.FullName}"); + + // Cache directories before we start copying + DirectoryInfo[] dirs = dir.GetDirectories(); + + // Create the destination directory + Directory.CreateDirectory(destinationDir); + + // Get the files in the source directory and copy to the destination directory + foreach (FileInfo file in dir.GetFiles()) + { + string targetFilePath = Path.Combine(destinationDir, file.Name); + file.CopyTo(targetFilePath); + } + + // If recursive and copying subdirectories, recursively call this method + if (recursive) + { + foreach (DirectoryInfo subDir in dirs) + { + string newDestinationDir = Path.Combine(destinationDir, subDir.Name); + CopyDirectory(subDir.FullName, newDestinationDir, true); + } + } + } + /// /// Format the string in language independent way. /// diff --git a/samples/video-translation/csharp/Common/CommonLib/Util/ExceptionHelper.cs b/samples/video-translation/csharp/CommonLib.Public/Util/ExceptionHelper.cs similarity index 100% rename from samples/video-translation/csharp/Common/CommonLib/Util/ExceptionHelper.cs rename to samples/video-translation/csharp/CommonLib.Public/Util/ExceptionHelper.cs diff --git a/samples/video-translation/csharp/CommonLib.Public/Util/PublicAppLogger.cs b/samples/video-translation/csharp/CommonLib.Public/Util/PublicAppLogger.cs new file mode 100644 index 000000000..556456bb0 --- /dev/null +++ b/samples/video-translation/csharp/CommonLib.Public/Util/PublicAppLogger.cs @@ -0,0 +1,27 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.CommonLib.TtsUtil; + +using System; +using Microsoft.SpeechServices.CommonLib.Public.Interface; + +public class PublicAppLogger : IAppLogger +{ + void IAppLogger.Log(string message) + { + Console.Write(message); + } + + void IAppLogger.LogLine(string message) + { + Console.WriteLine(message); + } + + void IAppLogger.LogLine() + { + Console.WriteLine(); + } +} diff --git a/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs new file mode 100644 index 000000000..0a701c344 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Iteration.cs @@ -0,0 +1,15 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; + +public partial class Iteration : StatefulResourceBase +{ + public IterationInput Input { get; set; } + + public IterationResult Result { get; set; } + + public string FailureReason { get; set; } +} diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs similarity index 92% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs index 906467385..2ce226c66 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/IterationInput.cs @@ -5,7 +5,7 @@ namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; -public class IterationInput +public partial class IterationInput { public int? SpeakerCount { get; set; } diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs similarity index 93% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs index 45a883526..3dafcb46f 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/IterationResult.cs @@ -7,7 +7,7 @@ namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public using System; -public class IterationResult +public partial class IterationResult { public Uri TranslatedVideoFileUrl { get; set; } diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs similarity index 74% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs index b0faa685c..b122055a6 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/PagedTranslation.cs @@ -7,6 +7,6 @@ namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; -public class PagedTranslation : PaginatedResources, IterationInput>> +public class PagedTranslation : PaginatedResources { } diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs similarity index 53% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs index 9f99356e2..f0a10e3b3 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/Translation.cs @@ -5,15 +5,13 @@ namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; -public class Translation : StatefulResourceBase - where TIteration : Iteration - where TIterationInput : IterationInput +public class Translation : StatefulResourceBase { public TranslationInput Input { get; set; } - public Iteration LatestIteration { get; set; } + public Iteration LatestIteration { get; set; } - public Iteration LatestSucceededIteration { get; set; } + public Iteration LatestSucceededIteration { get; set; } public string FailureReason { get; set; } } diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs similarity index 96% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs index 3e3feebe4..d7e30dd8e 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/DataContracts/DTOs/Public-2024-05-20-preview/TranslationInput.cs @@ -9,7 +9,7 @@ namespace Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public using System.Globalization; using System.Linq; -public class TranslationInput +public partial class TranslationInput { public CultureInfo SourceLocale { get; set; } diff --git a/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/VideoTranslationLib.Public.csproj b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/VideoTranslationLib.Public.csproj new file mode 100644 index 000000000..d340aca8f --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.Public/VideoTranslationLib.Public.csproj @@ -0,0 +1,28 @@ + + + + net8.0 + Microsoft.SpeechServices.VideoTranslationLib.Public + Microsoft.SpeechServices.VideoTranslationLib.Public + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/OperationStatus.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Enum/OperationStatus.cs similarity index 100% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/OperationStatus.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Enum/OperationStatus.cs diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/VoiceKind.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Enum/VoiceKind.cs similarity index 100% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/VoiceKind.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Enum/VoiceKind.cs diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/WebvttFileKind.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Enum/WebvttFileKind.cs similarity index 100% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Enum/WebvttFileKind.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Enum/WebvttFileKind.cs diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Operation.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Operation.cs similarity index 100% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/Operation.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/Operation.cs diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/WebvttFile.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/WebvttFile.cs similarity index 100% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/DataContracts/DTOs/Public-2024-05-20-preview/WebvttFile.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/DTOs/Public-2024-05-20-preview/WebvttFile.cs diff --git a/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/HttpClient/VideoTranslationPublicPreviewHttpClientConfig.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/HttpClient/VideoTranslationPublicPreviewHttpClientConfig.cs new file mode 100644 index 000000000..0bd6292dd --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/HttpClient/VideoTranslationPublicPreviewHttpClientConfig.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslation; + +using Flurl; +using Microsoft.SpeechServices.CommonLib; +using Microsoft.SpeechServices.CommonLib.Public.Interface; +using Microsoft.SpeechServices.CommonLib.Util; +using System; + +public class VideoTranslationPublicPreviewHttpClientConfig : + HttpClientConfigBase +{ + public VideoTranslationPublicPreviewHttpClientConfig(IRegionConfig regionConfig, string subKey) + : base(regionConfig, subKey) + { + } + + public override string RouteBase => "videotranslation"; + + public override bool IsApiVersionInUrlSegment => false; +} diff --git a/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/VideoTranslationLib.PublicBase.csproj b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/VideoTranslationLib.PublicBase.csproj new file mode 100644 index 000000000..435c159f1 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.PublicBase/VideoTranslationLib.PublicBase.csproj @@ -0,0 +1,13 @@ + + + + net8.0 + Microsoft.SpeechServices.VideoTranslationLib.PublicBase + Microsoft.SpeechServices.VideoTranslationLib.PublicBase + + + + + + + diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/IterationClient.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/IterationClient.cs similarity index 90% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/IterationClient.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/IterationClient.cs index 8cc21e01b..a0c23b7ce 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/IterationClient.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/IterationClient.cs @@ -19,10 +19,9 @@ namespace VideoTranslationPublicPreviewLib.HttpClient; using System.Net; using System.Threading.Tasks; -public class IterationClient : HttpClientBase - where TDeploymentEnvironment : Enum +public class IterationClient : HttpClientBase { - public IterationClient(HttpClientConfigBase config) + public IterationClient(HttpClientConfigBase config) : base(config) { } @@ -120,14 +119,19 @@ public async Task CreateIterationAndWaitUntilTerminatedAsync(this.Config); + var operationClient = new OperationClient(this.Config); await operationClient.QueryOperationUntilTerminateAsync(new Uri(operationLocation)).ConfigureAwait(false); @@ -140,7 +144,7 @@ public async Task CreateIterationAndWaitUntilTerminatedAsync CreateIterationAndWaitUntilTerminatedAsync() .ConfigureAwait(false); return (iterationResponse, response.Headers); @@ -199,7 +205,7 @@ private async Task CreateIterationWithResponseAsync( .AppendPathSegment(translationId) .AppendPathSegment("iterations") .AppendPathSegment(iteration.Id) - .WithHeader(CommonConst.Http.Headers.OperationId, operationId); + .WithHeader(CommonPublicConst.Http.Headers.OperationId, operationId); return await RequestWithRetryAsync(async () => { diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/OperationClient.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/OperationClient.cs similarity index 75% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/OperationClient.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/OperationClient.cs index d63e681e2..44569eb58 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/OperationClient.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/OperationClient.cs @@ -15,10 +15,9 @@ namespace VideoTranslationPublicPreviewLib.HttpClient; using System.Net; using System.Threading.Tasks; -public class OperationClient : HttpClientBase - where TDeploymentEnvironment : Enum +public class OperationClient : HttpClientBase { - public OperationClient(HttpClientConfigBase config) + public OperationClient(HttpClientConfigBase config) : base(config) { } @@ -32,7 +31,7 @@ public async Task QueryOperationUntilTerminateAsync( ArgumentNullException.ThrowIfNull(operation); Console.WriteLine($"Querying operation: {operationLocation}:"); var lastStatus = operation.Status; - Console.WriteLine(operation.Status.AsString()); + Console.WriteLine(operation.Status); while (new[] { OperationStatus.NotStarted, @@ -44,12 +43,12 @@ public async Task QueryOperationUntilTerminateAsync( if (operation.Status != lastStatus) { Console.WriteLine(); - Console.WriteLine(operation.Status.AsString()); + Console.WriteLine(operation.Status); lastStatus = operation.Status; } Console.Write("."); - await Task.Delay(CommonConst.Http.OperationQueryDuration).ConfigureAwait(false); + await Task.Delay(CommonPublicConst.Http.OperationQueryDuration).ConfigureAwait(false); } Console.WriteLine(); @@ -58,8 +57,8 @@ public async Task QueryOperationUntilTerminateAsync( public async Task GetOperationStringAsync(Uri operationLocation) { var url = operationLocation - .SetQueryParam("api-version", this.Config.ApiVersion) - .WithHeader("Ocp-Apim-Subscription-Key", this.Config.SubscriptionKey); + .SetQueryParam(CommonPublicConst.Http.ParameterNames.ApiVersion, this.Config.ApiVersion) + .WithHeader(CommonPublicConst.Http.Headers.SubscriptionKey, this.Config.SubscriptionKey); var response = await GetOperationWithResponseAsync(operationLocation).ConfigureAwait(false); return await response.GetStringAsync().ConfigureAwait(false); @@ -68,8 +67,8 @@ public async Task GetOperationStringAsync(Uri operationLocation) public async Task GetOperationAsync(Uri operationLocation) { var url = operationLocation - .SetQueryParam("api-version", this.Config.ApiVersion) - .WithHeader("Ocp-Apim-Subscription-Key", this.Config.SubscriptionKey); + .SetQueryParam(CommonPublicConst.Http.ParameterNames.ApiVersion, this.Config.ApiVersion) + .WithHeader(CommonPublicConst.Http.Headers.SubscriptionKey, this.Config.SubscriptionKey); var response = await GetOperationWithResponseAsync(operationLocation).ConfigureAwait(false); return await response.GetJsonAsync().ConfigureAwait(false); @@ -78,8 +77,8 @@ public async Task GetOperationAsync(Uri operationLocation) public async Task GetOperationWithResponseAsync(Uri operationLocation) { var url = operationLocation - .SetQueryParam("api-version", this.Config.ApiVersion) - .WithHeader("Ocp-Apim-Subscription-Key", this.Config.SubscriptionKey); + .SetQueryParam(CommonPublicConst.Http.ParameterNames.ApiVersion, this.Config.ApiVersion) + .WithHeader(CommonPublicConst.Http.Headers.SubscriptionKey, this.Config.SubscriptionKey); return await RequestWithRetryAsync(async () => { diff --git a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/TranslationClient.cs b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/TranslationClient.cs similarity index 72% rename from samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/TranslationClient.cs rename to samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/TranslationClient.cs index 3431f7409..9e57800ba 100644 --- a/samples/video-translation/csharp/Common/VideoTranslationLib.PublicPreview/HttpClient/TranslationClient.cs +++ b/samples/video-translation/csharp/VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/TranslationClient.cs @@ -15,16 +15,12 @@ namespace VideoTranslationPublicPreviewLib.HttpClient; using Newtonsoft.Json; using System; using System.IO; -using System.Linq; using System.Net; using System.Threading.Tasks; -public class TranslationClient : HttpClientBase - where TDeploymentEnvironment : Enum - where TIteration : Iteration - where TIterationInput : IterationInput +public class TranslationClient : HttpClientBase { - public TranslationClient(HttpClientConfigBase config) + public TranslationClient(HttpClientConfigBase config) : base(config) { } @@ -53,7 +49,7 @@ public async Task GetTranslationStringAsync(string translationId) return await response.GetStringAsync().ConfigureAwait(false); } - public async Task> GetTranslationAsync(string translationId) + public async Task GetTranslationAsync(string translationId) { var response = await GetTranslationResponseAsync(translationId).ConfigureAwait(false); @@ -63,7 +59,7 @@ public async Task> GetTranslationAsync( return null; } - return await response.GetJsonAsync>().ConfigureAwait(false); + return await response.GetJsonAsync().ConfigureAwait(false); } public async Task GetTranslationResponseAsync(string translationId) @@ -93,55 +89,52 @@ public async Task GetTranslationResponseAsync(string translation }).ConfigureAwait(false); } - public async Task>> GetTranslationsAsync() + public async Task> GetTranslationsAsync() { var url = BuildRequestBase(); return await RequestWithRetryAsync(async () => { - // var responseJson = await url.GetStringAsync().ConfigureAwait(false); return await url.GetAsync() - .ReceiveJson>>() + .ReceiveJson>() .ConfigureAwait(false); }).ConfigureAwait(false); } - public async Task> GetIterationsAsync(string translationId) + public async Task> GetIterationsAsync(string translationId) { var url = BuildRequestBase(); return await RequestWithRetryAsync(async () => { - // var responseJson = await url.GetStringAsync().ConfigureAwait(false); return await url .AppendPathSegment(translationId) .AppendPathSegment("iterations") .GetAsync() - .ReceiveJson>() + .ReceiveJson>() .ConfigureAwait(false); }).ConfigureAwait(false); } - public async Task GetIterationAsync(string translationId, string iterationId) + public async Task GetIterationAsync(string translationId, string iterationId) { var url = BuildRequestBase(); return await RequestWithRetryAsync(async () => { - // var responseJson = await url.GetStringAsync().ConfigureAwait(false); return await url .AppendPathSegment(translationId) .AppendPathSegment("iterations") .AppendPathSegment(iterationId) .GetAsync() - .ReceiveJson() + .ReceiveJson() .ConfigureAwait(false); }).ConfigureAwait(false); } - public async Task<(Translation translation, TIteration iteration)> CreateTranslationAndIterationAndWaitUntilTerminatedAsync( - Translation translation, - TIteration iteration) + public async Task<(Translation translation, Iteration iteration)> CreateTranslationAndIterationAndWaitUntilTerminatedAsync( + Translation translation, + Iteration iteration) { var transaltionResponse = await CreateTranslationAndWaitUntilTerminatedAsync( translation: translation).ConfigureAwait(false); @@ -151,9 +144,9 @@ public async Task GetIterationAsync(string translationId, string ite Console.WriteLine(JsonConvert.SerializeObject( transaltionResponse, Formatting.Indented, - CustomContractResolver.WriterSettings)); + CommonPublicConst.Json.WriterSettings)); - var iterationClient = new IterationClient(this.Config); + var iterationClient = new IterationClient(this.Config); var iterationResponse = await iterationClient.CreateIterationAndWaitUntilTerminatedAsync( translationId: transaltionResponse.Id, iteration: iteration, @@ -162,8 +155,8 @@ public async Task GetIterationAsync(string translationId, string ite return (transaltionResponse, iterationResponse); } - public async Task> CreateTranslationAndWaitUntilTerminatedAsync( - Translation translation) + public async Task CreateTranslationAndWaitUntilTerminatedAsync( + Translation translation) { Console.WriteLine($"Creating translation {translation.Id} :"); @@ -173,13 +166,13 @@ public async Task> CreateTranslationAnd operationId: operationId).ConfigureAwait(false); ArgumentNullException.ThrowIfNull(responseTranslation); - if (!createTranslationResponseHeaders.TryGetFirst(CommonConst.Http.Headers.OperationLocation, out var operationLocation) || + if (!createTranslationResponseHeaders.TryGetFirst(CommonPublicConst.Http.Headers.OperationLocation, out var operationLocation) || string.IsNullOrEmpty(operationLocation)) { - throw new InvalidDataException($"Missing header {CommonConst.Http.Headers.OperationLocation} in headers"); + throw new InvalidDataException($"Missing header {CommonPublicConst.Http.Headers.OperationLocation} in headers"); } - var operationClient = new OperationClient(this.Config); + var operationClient = new OperationClient(this.Config); await operationClient.QueryOperationUntilTerminateAsync(new Uri(operationLocation)).ConfigureAwait(false); @@ -187,8 +180,8 @@ public async Task> CreateTranslationAnd translationId: responseTranslation.Id).ConfigureAwait(false); } - public async Task<(Translation translation, IReadOnlyNameValueList headers)> CreateTranslationAsync( - Translation translation, + public async Task<(Translation translation, IReadOnlyNameValueList headers)> CreateTranslationAsync( + Translation translation, string operationId) { ArgumentNullException.ThrowIfNull(translation); @@ -196,13 +189,13 @@ public async Task> CreateTranslationAnd translation: translation, operationId: operationId); var response = await responseTask.ConfigureAwait(false); - var translationResponse = await response.GetJsonAsync>() + var translationResponse = await response.GetJsonAsync() .ConfigureAwait(false); return (translationResponse, response.Headers); } public async Task<(string responseString, IReadOnlyNameValueList headers)> CreateTranslationWithStringResponseAsync( - Translation translation, + Translation translation, string operationId) { ArgumentNullException.ThrowIfNull(translation); @@ -216,7 +209,7 @@ public async Task> CreateTranslationAnd } private async Task CreateTranslationWithResponseAsync( - Translation translation, + Translation translation, string operationId) { ArgumentNullException.ThrowIfNull(translation); @@ -225,7 +218,7 @@ private async Task CreateTranslationWithResponseAsync( var url = BuildRequestBase() .AppendPathSegment(translation.Id) - .WithHeader(CommonConst.Http.Headers.OperationId, operationId); + .WithHeader(CommonPublicConst.Http.Headers.OperationId, operationId); return await RequestWithRetryAsync(async () => { diff --git a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.sln b/samples/video-translation/csharp/VideoTranslationSample.sln similarity index 51% rename from samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.sln rename to samples/video-translation/csharp/VideoTranslationSample.sln index 11bd742c1..244b9134c 100644 --- a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.sln +++ b/samples/video-translation/csharp/VideoTranslationSample.sln @@ -1,17 +1,16 @@ - Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.10.35027.167 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommonLib", "..\Common\CommonLib\CommonLib.csproj", "{1E17112D-FC76-41C1-9009-E1831F237226}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoTranslationSample", "VideoTranslationSample\VideoTranslationSample.csproj", "{95F70A8E-FEA6-45F4-9C22-C9BDEA60544D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoTranslationLib.PublicPreview", "..\Common\VideoTranslationLib.PublicPreview\VideoTranslationLib.PublicPreview.csproj", "{DC18FF21-5F97-47AA-BE14-79D219B8183B}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Lib", "Lib", "{A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VideoTranslationLib.Common", "..\Common\VideoTranslationLib.Common\VideoTranslationLib.Common.csproj", "{B86258A9-9501-4080-AA11-AD598C8C7365}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonLib.Public", "CommonLib.Public\CommonLib.Public.csproj", "{F3F92734-D68A-4FD1-8D9D-E956FA1E03B3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoTranslationLib.Public", "VideoTranslationLib.Public\VideoTranslationLib.Public\VideoTranslationLib.Public.csproj", "{5BEE0999-8EB2-4E85-9842-0CD74A693776}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoTranslationLib.PublicBase", "VideoTranslationLib.Public\VideoTranslationLib.PublicBase\VideoTranslationLib.PublicBase.csproj", "{9099AF00-7D7E-4CD8-85E2-2A0251D32F7C}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -19,30 +18,30 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {1E17112D-FC76-41C1-9009-E1831F237226}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {1E17112D-FC76-41C1-9009-E1831F237226}.Debug|Any CPU.Build.0 = Debug|Any CPU - {1E17112D-FC76-41C1-9009-E1831F237226}.Release|Any CPU.ActiveCfg = Release|Any CPU - {1E17112D-FC76-41C1-9009-E1831F237226}.Release|Any CPU.Build.0 = Release|Any CPU {95F70A8E-FEA6-45F4-9C22-C9BDEA60544D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {95F70A8E-FEA6-45F4-9C22-C9BDEA60544D}.Debug|Any CPU.Build.0 = Debug|Any CPU {95F70A8E-FEA6-45F4-9C22-C9BDEA60544D}.Release|Any CPU.ActiveCfg = Release|Any CPU {95F70A8E-FEA6-45F4-9C22-C9BDEA60544D}.Release|Any CPU.Build.0 = Release|Any CPU - {DC18FF21-5F97-47AA-BE14-79D219B8183B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {DC18FF21-5F97-47AA-BE14-79D219B8183B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {DC18FF21-5F97-47AA-BE14-79D219B8183B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {DC18FF21-5F97-47AA-BE14-79D219B8183B}.Release|Any CPU.Build.0 = Release|Any CPU - {B86258A9-9501-4080-AA11-AD598C8C7365}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B86258A9-9501-4080-AA11-AD598C8C7365}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B86258A9-9501-4080-AA11-AD598C8C7365}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B86258A9-9501-4080-AA11-AD598C8C7365}.Release|Any CPU.Build.0 = Release|Any CPU + {F3F92734-D68A-4FD1-8D9D-E956FA1E03B3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F3F92734-D68A-4FD1-8D9D-E956FA1E03B3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F3F92734-D68A-4FD1-8D9D-E956FA1E03B3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F3F92734-D68A-4FD1-8D9D-E956FA1E03B3}.Release|Any CPU.Build.0 = Release|Any CPU + {5BEE0999-8EB2-4E85-9842-0CD74A693776}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5BEE0999-8EB2-4E85-9842-0CD74A693776}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5BEE0999-8EB2-4E85-9842-0CD74A693776}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5BEE0999-8EB2-4E85-9842-0CD74A693776}.Release|Any CPU.Build.0 = Release|Any CPU + {9099AF00-7D7E-4CD8-85E2-2A0251D32F7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9099AF00-7D7E-4CD8-85E2-2A0251D32F7C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9099AF00-7D7E-4CD8-85E2-2A0251D32F7C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9099AF00-7D7E-4CD8-85E2-2A0251D32F7C}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {1E17112D-FC76-41C1-9009-E1831F237226} = {A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4} - {DC18FF21-5F97-47AA-BE14-79D219B8183B} = {A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4} - {B86258A9-9501-4080-AA11-AD598C8C7365} = {A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4} + {F3F92734-D68A-4FD1-8D9D-E956FA1E03B3} = {A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4} + {5BEE0999-8EB2-4E85-9842-0CD74A693776} = {A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4} + {9099AF00-7D7E-4CD8-85E2-2A0251D32F7C} = {A9B28A07-F3F2-4EBF-B460-0492B5EDE1C4} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {B09F3B56-6D3D-4CF3-954C-D9308D6A1A68} diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/BaseOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/BaseOptions.cs new file mode 100644 index 000000000..2d859170a --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/BaseOptions.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; + +public partial class BaseOptions +{ + [Option('r', "region", Required = true, HelpText = "Specify region")] + public string Region { get; set; } + + [Option('s', "subscriptionKey", Required = true, HelpText = "Specify speech resource key.")] + public string SubscriptionKey { get; set; } + + [Option('v', "apiVersion", Required = true, HelpText = "Specify API version.")] + public string ApiVersion { get; set; } +} diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/CreateIterationAndWaitUntilTerminatedOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateIterationAndWaitUntilTerminatedOptions.cs new file mode 100644 index 000000000..c54abc9ff --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateIterationAndWaitUntilTerminatedOptions.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; +using Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; +using System; + +[Verb("createIterationAndWaitUntilTerminated", HelpText = "Create iteration.")] +public partial class CreateIterationAndWaitUntilTerminatedOptions : BaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } + + [Option('i', "iterationId", Required = true, HelpText = "Specify iteration ID.")] + public string IterationId { get; set; } + + [Option('n', "iterationName", Required = false, HelpText = "Specify iteration name, if not provided, will use iterationId as iterationName")] + public string IterationName { get; set; } + + [Option('c', "speakerCount", Required = false, HelpText = "Specify speaker count.")] + public int? SpeakerCount { get; set; } + + [Option('m', "subtitleMaxCharCountPerSegment", Required = false, HelpText = "Specify subtitle max visiable char count per segment.")] + public int? SubtitleMaxCharCountPerSegment { get; set; } + + [Option('e', "exportSubtitleInVideo", Required = false, HelpText = "Specify speaker count.")] + public bool? ExportSubtitleInVideo { get; set; } + + [Option('w', "webvttFileAzureBlobUrl", Required = false, HelpText = "Specify webvtt file Azure blob URL, it is required from secondary iteration.")] + public Uri WebvttFileAzureBlobUrl { get; set; } + + [Option('k', "webvttFileKind", Required = false, HelpText = "Specify webvtt file kind: SourceLocaleSubtitle, TargetLocaleSubtitle or MetadataJson, it is required from secondary iteration.")] + public WebvttFileKind? WebvttFileKind { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedBaseOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedBaseOptions.cs new file mode 100644 index 000000000..971a2f254 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedBaseOptions.cs @@ -0,0 +1,26 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; +using Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; +using System; + +public class CreateTranslationAndIterationAndWaitUntilTerminatedBaseOptions : CreateTranslationBaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } + + [Option('i', "iterationId", Required = true, HelpText = "Specify iteration ID.")] + public string IterationId { get; set; } + + [Option('w', "webvttFileAzureBlobUrl", Required = false, HelpText = "Specify webvtt file Azure blob URL, it is required from secondary iteration.")] + public Uri WebvttFileAzureBlobUrl { get; set; } + + [Option('k', "webvttFileKind", Required = false, HelpText = "Specify webvtt file kind: SourceLocaleSubtitle, TargetLocaleSubtitle or MetadataJson, it is required from secondary iteration.")] + public WebvttFileKind? WebvttFileKind { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedOptions.cs new file mode 100644 index 000000000..37fedd6e0 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationAndIterationAndWaitUntilTerminatedOptions.cs @@ -0,0 +1,17 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; +using System; + +[Verb("createTranslationAndIterationAndWaitUntilTerminated", HelpText = "Create translation and create first iteration until terminated.")] +public partial class CreateTranslationAndIterationAndWaitUntilTerminatedOptions : CreateTranslationAndIterationAndWaitUntilTerminatedBaseOptions +{ + [Option('v', "videoFileAzureBlobUrl", Required = true, HelpText = "Specify video file Azure blob URL.")] + public Uri VideoFileAzureBlobUrl { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationBaseOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationBaseOptions.cs new file mode 100644 index 000000000..65f222ddd --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationBaseOptions.cs @@ -0,0 +1,39 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; +using System; +using System.Globalization; +using VoiceKind = Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview.VoiceKind; + +public partial class CreateTranslationBaseOptions : BaseOptions +{ + [Option('l', "sourceLocale", Required = true, HelpText = "Specify source locale of the video.")] + public CultureInfo SourceLocale { get; set; } + + [Option('a', "targetLocale", Required = true, HelpText = "Specify target locale of the video.")] + public CultureInfo TargetLocale { get; set; } + + [Option('v', "voiceKind", Required = true, HelpText = "Specify voice kind: PlatformVoice or PersonalVoice.")] + public VoiceKind VoiceKind { get; set; } + + [Option('c', "speakerCount", Required = false, HelpText = "Specify speaker count.")] + public int? SpeakerCount { get; set; } + + [Option('m', "subtitleMaxCharCountPerSegment", Required = false, HelpText = "Specify subtitle max visiable char count per segment.")] + public int? SubtitleMaxCharCountPerSegment { get; set; } + + [Option('e', "exportSubtitleInVideo", Required = false, HelpText = "Specify speaker count.")] + public bool? ExportSubtitleInVideo { get; set; } + + [Option('n', "translationName", Required = false, HelpText = "Specify translation name.")] + public string TranslationName { get; set; } + + [Option('d', "translationDescription", Required = false, HelpText = "Specify translation description.")] + public string TranslationDescription { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationOptions.cs new file mode 100644 index 000000000..c4b32a41e --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/CreateTranslationOptions.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; +using System; + +[Verb("createTranslation", HelpText = "Create translation.")] +public partial class CreateTranslationOptions : CreateTranslationBaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } + + [Option('v', "videoFileAzureBlobUrl", Required = true, HelpText = "Specify video file Azure blob URL.")] + public Uri VideoFileAzureBlobUrl { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/DeleteTranslationOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/DeleteTranslationOptions.cs new file mode 100644 index 000000000..c05c187b4 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/DeleteTranslationOptions.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; + +[Verb("deleteTranslation", HelpText = "Delete translation by ID.")] +public class DeleteTranslationOptions : BaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationOptions.cs new file mode 100644 index 000000000..68fa987f0 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationOptions.cs @@ -0,0 +1,19 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; + +[Verb("queryIteration", HelpText = "Query iteration by translation ID and iteration ID.")] +public class QueryIterationOptions : BaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } + + [Option('i', "iterationId", Required = true, HelpText = "Specify iteration ID.")] + public string IterationId { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationsOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationsOptions.cs new file mode 100644 index 000000000..c2b3f3684 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryIterationsOptions.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; + +[Verb("queryIterations", HelpText = "Query iterations.")] +public class QueryIterationsOptions : BaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationOptions.cs new file mode 100644 index 000000000..5942e3013 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationOptions.cs @@ -0,0 +1,16 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; + +[Verb("queryTranslation", HelpText = "Query translation by ID.")] +public class QueryTranslationOptions : BaseOptions +{ + [Option('t', "translationId", Required = true, HelpText = "Specify translation ID.")] + public string TranslationId { get; set; } +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationsOptions.cs b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationsOptions.cs new file mode 100644 index 000000000..04361dc60 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Options/QueryTranslationsOptions.cs @@ -0,0 +1,14 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; + +using CommandLine; + +[Verb("queryTranslations", HelpText = "Query translations.")] +public class QueryTranslationsOptions : BaseOptions +{ +} + diff --git a/samples/video-translation/csharp/VideoTranslationSample/Program.cs b/samples/video-translation/csharp/VideoTranslationSample/Program.cs new file mode 100644 index 000000000..652d608c6 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/Program.cs @@ -0,0 +1,246 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. +// + +namespace Microsoft.SpeechServices.VideoTranslation.ApiSampleCode.PublicPreview; + +using CommandLine; +using Microsoft.SpeechServices.CommonLib; +using Microsoft.SpeechServices.CommonLib.Public.Interface; +using Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; +using Microsoft.SpeechServices.VideoTranslationSample.PublicPreview; +using Newtonsoft.Json; +using System; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using VideoTranslationPublicPreviewLib.HttpClient; + +internal class Program +{ + static async Task Main(string[] args) + { + var types = LoadVerbs(); + + var exitCode = await Parser.Default.ParseArguments(args, types) + .MapResult( + options => RunAndReturnExitCodeAsync(options), + _ => Task.FromResult(1)); + + if (exitCode == 0) + { + Console.WriteLine("Process completed successfully."); + } + else + { + Console.WriteLine($"Failure with exit code: {exitCode}"); + } + + return exitCode; + } + + static async Task RunAndReturnExitCodeAsync(object options) + { + var optionsBase = options as BaseOptions; + ArgumentNullException.ThrowIfNull(optionsBase); + try + { + return await DoRunAndReturnExitCodeAsync(optionsBase).ConfigureAwait(false); + } + catch (Exception e) + { + Console.WriteLine($"Failed to run with exception: {e.Message}"); + return CommonPublicConst.ExistCodes.GenericError; + } + } + + static async Task DoRunAndReturnExitCodeAsync(BaseOptions baseOptions) + { + ArgumentNullException.ThrowIfNull(baseOptions); + var regionConfig = new ApimApiRegionConfig(baseOptions.Region); + + var httpConfig = new VideoTranslationPublicPreviewHttpClientConfig( + regionConfig: regionConfig, + subKey: baseOptions.SubscriptionKey) + { + ApiVersion = string.IsNullOrEmpty(baseOptions.ApiVersion) ? + CommonPublicConst.ApiVersions.ApiVersion20240520Preview : baseOptions.ApiVersion, + }; + + var translationClient = new TranslationClient(httpConfig); + + var iterationClient = new IterationClient(httpConfig); + + var operationClient = new OperationClient(httpConfig); + + switch (baseOptions) + { + case CreateTranslationOptions options: + { + var translation = new Translation() + { + Id = options.TranslationId, + DisplayName = options.TranslationName, + Description = options.TranslationDescription, + Input = new TranslationInput() + { + SourceLocale = options.SourceLocale, + TargetLocale = options.TargetLocale, + VoiceKind = options.VoiceKind, + SpeakerCount = options.SpeakerCount, + SubtitleMaxCharCountPerSegment = options.SubtitleMaxCharCountPerSegment, + ExportSubtitleInVideo = options.ExportSubtitleInVideo, + VideoFileUrl = options.VideoFileAzureBlobUrl, + }, + }; + + var operationId = Guid.NewGuid().ToString(); + (translation, var headers) = await translationClient.CreateTranslationAsync( + translation: translation, + operationId: operationId).ConfigureAwait(false); + + Console.WriteLine(); + Console.WriteLine("Created translation:"); + Console.WriteLine(JsonConvert.SerializeObject( + translation, + Formatting.Indented, + CommonPublicConst.Json.WriterSettings)); + break; + } + + case QueryTranslationsOptions options: + { + var translations = await translationClient.GetTranslationsAsync().ConfigureAwait(false); + Console.WriteLine(JsonConvert.SerializeObject( + translations, + Formatting.Indented, + CommonPublicConst.Json.WriterSettings)); + break; + } + + case QueryTranslationOptions options: + { + var translation = await translationClient.GetTranslationAsync( + options.TranslationId).ConfigureAwait(false); + Console.WriteLine(JsonConvert.SerializeObject( + translation, + Formatting.Indented, + CommonPublicConst.Json.WriterSettings)); + break; + } + + case DeleteTranslationOptions options: + { + var response = await translationClient.DeleteTranslationAsync( + options.TranslationId).ConfigureAwait(false); + Console.WriteLine(response.StatusCode); + break; + } + + case CreateIterationAndWaitUntilTerminatedOptions options: + { + var iteration = new Iteration() + { + Id = options.IterationId, + DisplayName = string.IsNullOrEmpty(options.IterationName) ? + options.IterationId : options.IterationName, + Input = new IterationInput() + { + SpeakerCount = options.SpeakerCount, + SubtitleMaxCharCountPerSegment = options.SubtitleMaxCharCountPerSegment, + ExportSubtitleInVideo = options.ExportSubtitleInVideo, + WebvttFile = options.WebvttFileAzureBlobUrl == null ? null : new WebvttFile() + { + Kind = options.WebvttFileKind ?? WebvttFileKind.TargetLocaleSubtitle, + Url = options.WebvttFileAzureBlobUrl, + } + } + }; + + var iterationResponse = await iterationClient.CreateIterationAndWaitUntilTerminatedAsync( + translationId: options.TranslationId, + iteration: iteration, + additionalHeaders: null).ConfigureAwait(false); + break; + } + + case QueryIterationsOptions options: + { + var translations = await translationClient.GetIterationsAsync( + options.TranslationId).ConfigureAwait(false); + Console.WriteLine(JsonConvert.SerializeObject( + translations, + Formatting.Indented, + CommonPublicConst.Json.WriterSettings)); + break; + } + + case QueryIterationOptions options: + { + var translations = await translationClient.GetIterationAsync( + translationId: options.TranslationId, + iterationId: options.IterationId).ConfigureAwait(false); + Console.WriteLine(JsonConvert.SerializeObject( + translations, + Formatting.Indented, + CommonPublicConst.Json.WriterSettings)); + break; + } + + case CreateTranslationAndIterationAndWaitUntilTerminatedOptions options: + { + var iteration = new Iteration() + { + Id = options.IterationId, + DisplayName = options.IterationId, + Input = new IterationInput() + { + SpeakerCount = options.SpeakerCount, + SubtitleMaxCharCountPerSegment = options.SubtitleMaxCharCountPerSegment, + ExportSubtitleInVideo = options.ExportSubtitleInVideo, + WebvttFile = options.WebvttFileAzureBlobUrl == null ? null : new WebvttFile() + { + Kind = options.WebvttFileKind ?? WebvttFileKind.TargetLocaleSubtitle, + Url = options.WebvttFileAzureBlobUrl, + } + } + }; + + var translation = new Translation() + { + Id = options.TranslationId, + DisplayName = options.TranslationId, + Description = options.TranslationId, + Input = new TranslationInput() + { + SourceLocale = options.SourceLocale, + TargetLocale = options.TargetLocale, + VoiceKind = options.VoiceKind, + SpeakerCount = iteration.Input?.SpeakerCount, + SubtitleMaxCharCountPerSegment = iteration.Input?.SubtitleMaxCharCountPerSegment, + ExportSubtitleInVideo = iteration.Input?.ExportSubtitleInVideo, + VideoFileUrl = options.VideoFileAzureBlobUrl, + } + }; + + (translation, iteration) = await translationClient.CreateTranslationAndIterationAndWaitUntilTerminatedAsync( + translation: translation, + iteration: iteration).ConfigureAwait(false); + break; + } + + default: + throw new NotSupportedException(); + } + + return CommonPublicConst.ExistCodes.NoError; + } + + //load all types using Reflection + private static Type[] LoadVerbs() + { + return Assembly.GetExecutingAssembly().GetTypes() + .Where(t => t.GetCustomAttribute() != null).ToArray(); + } +} diff --git a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.csproj b/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.csproj new file mode 100644 index 000000000..480a9afa6 --- /dev/null +++ b/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample.csproj @@ -0,0 +1,24 @@ + + + + Exe + net8.0 + Microsoft.SpeechServices.VideoTranslationSample + VideoTranslationSample + + + + + + + + + + + + + + + + + diff --git a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Arguments.cs b/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Arguments.cs deleted file mode 100644 index 5e93b43cb..000000000 --- a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Arguments.cs +++ /dev/null @@ -1,230 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslation.ApiSampleCode.PublicPreview; - -using Microsoft.SpeechServices.CommonLib.Attributes; -using Microsoft.SpeechServices.CommonLib.CommandParser; -using Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; -using System; -using System.Globalization; - -[Comment("VideoTranslation tool.")] -public class Arguments - where TDeploymentEnvironment : System.Enum -{ - [Argument( - "mode", - Description = "Specifies the execute modes.", - Optional = false, - UsagePlaceholder = "mode", - RequiredModes = "CreateTranslation,QueryTranslations,QueryTranslation,DeleteTranslation,CreateIteration,QueryIterations,QueryIteration,CreateConsent,QueryConsents,QueryConsent,DeleteConsent,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string modeString = string.Empty; - - [Argument( - "apiVersion", - Description = "Specifies the api version: 2024-05-20-preview or 2024-07-30-preview", - Optional = true, - UsagePlaceholder = "apiVersion", - RequiredModes = "CreateTranslation,QueryTranslations,QueryTranslation,DeleteTranslation,CreateIteration,QueryIterations,QueryIteration,CreateConsent,QueryConsents,QueryConsent,DeleteConsent,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string apiVersion = string.Empty; - - [Argument( - "region", - Description = "Specifies the environment: eastus", - Optional = false, - UsagePlaceholder = "eastus", - RequiredModes = "CreateTranslation,QueryTranslations,QueryTranslation,DeleteTranslation,CreateIteration,QueryIterations,QueryIteration,CreateConsent,QueryConsents,QueryConsent,DeleteConsent,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string regionString = string.Empty; - - [Argument( - "subscriptionKey", - Description = "Specifies speech subscription key.", - Optional = false, - UsagePlaceholder = "subscriptionKey", - RequiredModes = "CreateTranslation,QueryTranslations,QueryTranslation,DeleteTranslation,CreateIteration,QueryIterations,QueryIteration,CreateConsent,QueryConsents,QueryConsent,DeleteConsent,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string subscriptionKey = string.Empty; - - [Argument( - "translationId", - Description = "Specifies the translation resource ID", - Optional = true, - UsagePlaceholder = "translationId", - RequiredModes = "CreateTranslation,QueryTranslation,DeleteTranslation,CreateIteration,QueryIteration,CreateTranslationAndIterationAndWaitUntilTerminated,QueryIterations")] - private string translationId = string.Empty; - - [Argument( - "iterationId", - Description = "Specifies the iteration resource ID", - Optional = true, - UsagePlaceholder = "iterationId", - RequiredModes = "CreateIteration,QueryIteration,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string iterationId = string.Empty; - - [Argument( - "sourceLocale", - Description = "Specifies the source locale e.g. en-US, zh-CN", - Optional = true, - UsagePlaceholder = "en-US", - RequiredModes = "CreateTranslation,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string sourceLocaleString = string.Empty; - - [Argument( - "targetLocale", - Description = "Specifies the target locale e.g. en-US, zh-CN", - Optional = true, - UsagePlaceholder = "zh-CN", - OptionalModes = "CreateTranslation,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string targetLocaleString = string.Empty; - - [Argument( - "videoFileAzureBlobUrl", - Description = "Specifies path of input video file azure blob URL.", - Optional = true, - UsagePlaceholder = "videoFileAzureBlobUrl", - RequiredModes = "CreateTranslation,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string videoFileAzureBlobUrl = string.Empty; - - [Argument( - "webvttFileAzureBlobUrl", - Description = "Specifies path of input webvtt file azure blob URL.", - Optional = true, - UsagePlaceholder = "webvttFileAzureBlobUrl", - OptionalModes = "CreateIteration,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string webvttFileAzureBlobUrl = string.Empty; - - [Argument( - "webvttFileKind", - Description = "Specifies webvtt file kind: MetadataJson(default), SourceLocaleSubtitle or TargetLocaleSubtitle.", - Optional = true, - UsagePlaceholder = "MetadataJson(default)/SourceLocaleSubtitle/TargetLocaleSubtitle", - OptionalModes = "CreateIteration,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string webvttFileKind = string.Empty; - - [Argument( - "voiceKind", - Description = "Specifies TTS synthesis voice kind: PlatformVoice or PersonalVoice", - Optional = true, - UsagePlaceholder = "PlatformVoice(default)/PersonalVoice", - RequiredModes = "CreateTranslation,CreateTranslationAndIterationAndWaitUntilTerminated")] - private string voiceKindString = string.Empty; - - [Argument( - "subtitleMaxCharCountPerSegment", - Description = "Subtitle max char per segment.", - Optional = true, - OptionalModes = "CreateIteration,CreateTranslationAndIterationAndWaitUntilTerminated")] - private int subtitleMaxCharCountPerSegment = 0; - - [Argument( - "speakerCount", - Description = "Max speaker count.", - Optional = true, - OptionalModes = "CreateIteration,CreateTranslationAndIterationAndWaitUntilTerminated")] - private int speakerCount = 0; - - [Argument( - "exportSubtitleInVideo", - Description = "Whether export subtitle in video.", - Optional = true, - UsagePlaceholder = "exportSubtitleInVideo", - OptionalModes = "CreateIteration,CreateTranslationAndIterationAndWaitUntilTerminated")] - private bool exportSubtitleInVideo = false; - - public Mode Mode - { - get - { - if (!Enum.TryParse(this.modeString, true, out var mode)) - { - throw new ArgumentException($"Invalid mode arguments."); - } - - return mode; - } - } - - public string ApiVersion => this.apiVersion; - - public TDeploymentEnvironment Environment - { - get - { - if (string.IsNullOrEmpty(this.regionString)) - { - throw new ArgumentNullException(nameof(this.regionString)); - } - - return DeploymentEnvironmentAttribute.ParseFromRegionIdentifier(this.regionString); - } - } - - public string SpeechSubscriptionKey => this.subscriptionKey; - - public string TranslationId => this.translationId; - - public string IterationId => this.iterationId; - - public CultureInfo TypedSourceLocale - { - get - { - if (string.IsNullOrEmpty(this.sourceLocaleString)) - { - return null; - } - - return CultureInfo.CreateSpecificCulture(this.sourceLocaleString); - } - } - - public CultureInfo TypedTargetLocale - { - get - { - if (string.IsNullOrEmpty(this.targetLocaleString)) - { - return null; - } - - return CultureInfo.CreateSpecificCulture(this.targetLocaleString); - } - } - - public Uri TypedVideoFileAzureBlobUrl => string.IsNullOrWhiteSpace(this.videoFileAzureBlobUrl) ? - null : new Uri(this.videoFileAzureBlobUrl); - - public Uri TypedWebvttFileAzureBlobUrl => string.IsNullOrWhiteSpace(this.webvttFileAzureBlobUrl) ? - null : new Uri(this.webvttFileAzureBlobUrl); - - public WebvttFileKind? TypedWebvttFileKind => string.IsNullOrWhiteSpace(this.webvttFileKind) ? - null : Enum.Parse(this.webvttFileKind); - - public VoiceKind? TypedVoiceKind - { - get - { - if (!string.IsNullOrEmpty(this.voiceKindString)) - { - if (Enum.TryParse(this.voiceKindString, true, out var voiceKind)) - { - return voiceKind; - } - else - { - throw new NotSupportedException(this.voiceKindString); - } - } - - return null; - } - } - - public int? SubtitleMaxCharCountPerSegment => this.subtitleMaxCharCountPerSegment == 0 ? null : this.subtitleMaxCharCountPerSegment; - - public int? SpeakerCount => this.speakerCount == 0 ? null : this.speakerCount; - - public bool? ExportSubtitleInVideo => this.exportSubtitleInVideo ? true : null; -} diff --git a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Mode.cs b/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Mode.cs deleted file mode 100644 index a1c85ed9a..000000000 --- a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Mode.cs +++ /dev/null @@ -1,29 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslation.ApiSampleCode.PublicPreview; - -public enum Mode -{ - None = 0, - - // Combined operations. - CreateTranslationAndIterationAndWaitUntilTerminated, - - // Atom operations. - CreateTranslation, - - QueryTranslations, - - QueryTranslation, - - DeleteTranslation, - - CreateIteration, - - QueryIterations, - - QueryIteration, -} \ No newline at end of file diff --git a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Program.cs b/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Program.cs deleted file mode 100644 index 253b45134..000000000 --- a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/Program.cs +++ /dev/null @@ -1,198 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE.md file in the project root for full license information. -// - -namespace Microsoft.SpeechServices.VideoTranslation.ApiSampleCode.PublicPreview; - -using Microsoft.SpeechServices.CommonLib; -using Microsoft.SpeechServices.CommonLib.CommandParser; -using Microsoft.SpeechServices.CommonLib.Util; -using Microsoft.SpeechServices.Cris.Http.DTOs.Public.VideoTranslation.Public20240520Preview; -using Microsoft.SpeechServices.CustomVoice.TtsLib.Util; -using Microsoft.SpeechServices.VideoTranslationLib.Enums; -using Microsoft.SpeechServices.VideoTranslationLib.PublicPreview.Base; -using Microsoft.VisualBasic; -using Newtonsoft.Json; -using System; -using System.Threading.Tasks; -using VideoTranslationPublicPreviewLib.HttpClient; - -internal class Program -{ - static async Task Main(string[] args) - { - ConsoleMaskSasHelper.ShowSas = true; - return await ConsoleApp>.RunAsync( - args, - ProcessAsync).ConfigureAwait(false); - } - - public static async Task ProcessAsync( - Arguments args) - where TDeploymentEnvironment : Enum - { - try - { - var httpConfig = new VideoTranslationPublicPreviewHttpClientConfig( - args.Environment, - args.SpeechSubscriptionKey) - { - ApiVersion = args.ApiVersion, - }; - - var translationClient = new TranslationClient, IterationInput>(httpConfig); - - var iterationClient = new IterationClient(httpConfig); - - var operationClient = new OperationClient(httpConfig); - - switch (args.Mode) - { - case Mode.CreateTranslationAndIterationAndWaitUntilTerminated: - { - var iteration = new Iteration() - { - Id = args.IterationId, - DisplayName = args.IterationId, - Input = new IterationInput() - { - SpeakerCount = args.SpeakerCount, - SubtitleMaxCharCountPerSegment = args.SubtitleMaxCharCountPerSegment, - ExportSubtitleInVideo = args.ExportSubtitleInVideo, - WebvttFile = args.TypedWebvttFileAzureBlobUrl == null ? null : new WebvttFile() - { - Kind = args.TypedWebvttFileKind ?? WebvttFileKind.TargetLocaleSubtitle, - Url = args.TypedWebvttFileAzureBlobUrl, - } - } - }; - - var voiceKind = args.TypedVoiceKind ?? VoiceKind.PlatformVoice; - var fileName = UriHelper.GetFileName(args.TypedVideoFileAzureBlobUrl); - var translation = new Translation, IterationInput>() - { - Id = args.TranslationId, - DisplayName = fileName, - Description = $"Translation {fileName} from {args.TypedSourceLocale} to {args.TypedTargetLocale} with {voiceKind.AsString()}", - Input = new TranslationInput() - { - SpeakerCount = iteration.Input?.SpeakerCount, - SubtitleMaxCharCountPerSegment = iteration.Input?.SubtitleMaxCharCountPerSegment, - ExportSubtitleInVideo = iteration.Input?.ExportSubtitleInVideo, - SourceLocale = args.TypedSourceLocale, - TargetLocale = args.TypedTargetLocale, - VoiceKind = voiceKind, - VideoFileUrl = args.TypedVideoFileAzureBlobUrl, - } - }; - - (translation, iteration) = await translationClient.CreateTranslationAndIterationAndWaitUntilTerminatedAsync( - translation: translation, - iteration: iteration).ConfigureAwait(false); - break; - } - - case Mode.CreateTranslation: - { - await ConsoleAppHelper.CreateTranslationAsync( - translationClient: translationClient, - translationId: args.TranslationId, - sourceLocale: args.TypedSourceLocale, - targetLocale: args.TypedTargetLocale, - voiceKind: args.TypedVoiceKind ?? VoiceKind.PlatformVoice, - videoFileUrl: args.TypedVideoFileAzureBlobUrl, - speakerCount: args.SpeakerCount).ConfigureAwait(false); - break; - } - - case Mode.QueryTranslations: - { - var translations = await translationClient.GetTranslationsAsync().ConfigureAwait(false); - Console.WriteLine(JsonConvert.SerializeObject( - translations, - Formatting.Indented, - CustomContractResolver.WriterSettings)); - break; - } - - case Mode.QueryTranslation: - { - var translation = await translationClient.GetTranslationAsync( - args.TranslationId).ConfigureAwait(false); - Console.WriteLine(JsonConvert.SerializeObject( - translation, - Formatting.Indented, - CustomContractResolver.WriterSettings)); - break; - } - - case Mode.DeleteTranslation: - { - var response = await translationClient.DeleteTranslationAsync(args.TranslationId).ConfigureAwait(false); - Console.WriteLine(response.StatusCode); - break; - } - - case Mode.CreateIteration: - { - var iteration = new Iteration() - { - Id = args.IterationId, - DisplayName = args.IterationId, - Input = new IterationInput() - { - SpeakerCount = args.SpeakerCount, - SubtitleMaxCharCountPerSegment = args.SubtitleMaxCharCountPerSegment, - ExportSubtitleInVideo = args.ExportSubtitleInVideo, - WebvttFile = args.TypedWebvttFileAzureBlobUrl == null ? null : new WebvttFile() - { - Kind = args.TypedWebvttFileKind ?? WebvttFileKind.TargetLocaleSubtitle, - Url = args.TypedWebvttFileAzureBlobUrl, - } - } - }; - - var iterationResponse = await iterationClient.CreateIterationAndWaitUntilTerminatedAsync( - translationId: args.TranslationId, - iteration: iteration, - additionalHeaders: null).ConfigureAwait(false); - break; - } - - case Mode.QueryIterations: - { - var translations = await translationClient.GetIterationsAsync(args.TranslationId).ConfigureAwait(false); - Console.WriteLine(JsonConvert.SerializeObject( - translations, - Formatting.Indented, - CustomContractResolver.WriterSettings)); - break; - } - - case Mode.QueryIteration: - { - var translations = await translationClient.GetIterationAsync(args.TranslationId, args.IterationId).ConfigureAwait(false); - Console.WriteLine(JsonConvert.SerializeObject( - translations, - Formatting.Indented, - CustomContractResolver.WriterSettings)); - break; - } - - default: - throw new NotSupportedException(args.Mode.AsString()); - } - } - catch (Exception e) - { - Console.WriteLine($"Failed to run with exception: {e.Message}"); - return ExitCode.GenericError; - } - - Console.WriteLine(); - Console.WriteLine("Process completed successfully."); - - return ExitCode.NoError; - } -} diff --git a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/VideoTranslationSample.csproj b/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/VideoTranslationSample.csproj deleted file mode 100644 index 50ac3490a..000000000 --- a/samples/video-translation/csharp/VideoTranslationSample/VideoTranslationSample/VideoTranslationSample.csproj +++ /dev/null @@ -1,16 +0,0 @@ - - - - Exe - net7.0 - Microsoft.SpeechServices.VideoTranslation.ApiSampleCode.PublicPreview - Microsoft.SpeechServices.VideoTranslation.ApiSampleCode.PublicPreview - - - - - - - - - diff --git a/samples/video-translation/csharp/readme.md b/samples/video-translation/csharp/readme.md index a350a0e48..63eb34f95 100644 --- a/samples/video-translation/csharp/readme.md +++ b/samples/video-translation/csharp/readme.md @@ -2,9 +2,31 @@ Video translation client tool and API sample code -# Solution: - [VideoTranslationApiSampleCode.sln](VideoTranslationSample/VideoTranslationSample.sln) +# Supported OS +## Windows prerequisite: + Install [dotnet 8.0](https://dotnet.microsoft.com/download/dotnet/8.0) + + Run tool: VideoTranslationSample.exe [verb] [arguments] + +## Linux prerequisite: + Install [dotnet 8.0](https://dotnet.microsoft.com/download/dotnet/8.0) + + Run tool: dotnet VideoTranslationSample.dll [verb] [arguments] + +# Work Flow + + 1. Upload video file to Azure storage blob, and then create translation and run first iteration with below command: + > VideoTranslationSample createTranslationAndIterationAndWaitUntilTerminated --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --sourceLocale [SourceLocale] --targetLocales [TargetLocale] --voiceKind [PersonalVoice/PlatformVoice] -videoFileAzureBlobUrl [VideoFileAzureBlobUrl] + + 2. Download translated metadata json webvtt file to local, and modify it for content editing. + You can use [Subtitle Edit Tool](https://github.com/SubtitleEdit/subtitleedit) for assistance. + + 3. Upload modified metadata json webvtt file to Azure storage blob, and then create another iteration with below command: + > VideoTranslationSample createIterationAndWaitUntilTerminated --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --translationId [TranslationId] -iterationId [IterationId] + +# Solution: + [VideoTranslationApiSampleCode.sln](VideoTranslationSample.sln) # API sample: @@ -12,59 +34,67 @@ Video translation client tool and API sample code For RESTful API usage reference below API core library class. ## RESTful API core library: - Translation API core library: [TranslationClient.cs](Common/VideoTranslationLib.PublicPreview.Base/HttpClient/TranslationClient.cs) + Translation API core library: [TranslationClient.cs](VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/TranslationClient.cs) - Iteration API core library: [TranslationClient.cs](Common/VideoTranslationLib.PublicPreview.Base/HttpClient/IterationClient.cs) + Iteration API core library: [IterationClient.cs](VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/IterationClient.cs) - Operation API core library: [TranslationClient.cs](Common/VideoTranslationLib.PublicPreview.Base/HttpClient/OperationClient.cs) + Operation API core library: [OperationClient.cs](VideoTranslationLib.Public/VideoTranslationLib.ReferenceFiles/HttpClient/OperationClient.cs) # For project CommonLib Do not upgrade Flurl to version 4.0 because it does not support NewtonJson for ReceiveJson. -# Supported OS - ## Windows - Microsoft.VideoTranslationClient.exe - -# Runn tool on Windows prerequisite: - [Install dotnet 7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) -# Command line sample - | Description | Command Sample | +# Command Line Usage + | Description | Command line arguments | | ------------ | -------------- | - | Upload the new video file for translation and run the first iteration of the translation. | -mode CreateTranslationAndIterationAndWaitUntilTerminated -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -sourceLocale zh-CN -targetLocales en-US -VoiceKind PersonalVoice -videoFileAzureBlobUrl VideoFileAzureBlobUrl | - | Create a translation for the video file. | -mode CreateTranslation -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -sourceLocale zh-CN -targetLocale en-US -voiceKind PlatformVoice -translationId translationId -videoFileAzureBlobUrl VideoFileAzureBlobUrl | - | Query the translations. | -mode QueryTranslations -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview | - | Query the translation by ID. | -mode QueryTranslation -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -translationId translationId | - | Delete the translation by ID. | -mode DeleteTranslation -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -translationId translationId | - | Create an iteration for the translation. | -mode CreateIteration -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -translationId translationId -iterationId iterationId | - | Query the iterations. | -mode QueryIterations -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -translationId translationId | - | Query the iteration by ID. | -mode QueryIteration -region eastus -subscriptionKey subscriptionKey -apiVersion 2024-05-20-preview -translationId translationId -iterationId iterationId | + | Upload the new video file for translation and run the first iteration of the translation. | createTranslationAndIterationAndWaitUntilTerminated --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --sourceLocale [SourceLocale] --targetLocales [TargetLocale] --voiceKind [PersonalVoice/PlatformVoice] --videoFileAzureBlobUrl [VideoFileAzureBlobUrl] | + | Create a translation for the video file. | createTranslation --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --sourceLocale [SourceLocale] --targetLocale [TargetLocale] --voiceKind [PersonalVoice/PlatformVoice] --translationId [TranslationId] --videoFileAzureBlobUrl [VideoFileAzureBlobUrl] | + | Query the translations. | queryTranslations --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] | + | Query the translation by ID. | queryTranslation --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --translationId [TranslationId] | + | Delete the translation by ID. | deleteTranslation --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --translationId [TranslationId] | + | Create an iteration for the translation and wait until its terminated. | createIterationAndWaitUntilTerminated --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --translationId [TranslationId] --iterationId [IterationId] | + | Query the iterations. | queryIterations --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --translationId [TranslationId] | + | Query the iteration by ID. | queryIteration --region [RegionIdentifier] --subscriptionKey [YourSpeechResourceKey] --apiVersion [ApiVersion] --translationId [TranslationId] --iterationId [IterationId] | # Command line tool arguments - | Argument | Supported Values Sample | Description | - | -------- | ---------------- | ----------- | - | -region | eastus | Provide the region of the API request. | - | -subscriptionKey | | Provide your speech resource key. | - | -apiVersion | 2024-05-20-preview | Provide the version of the API request. | - | -VoiceKind | PlatformVoice/PersonalVoice | Synthesize TTS for the translated target video using either PlatformVoice or PersonalVoice. | - | -sourceLocale | en-US | The locale of the input video file. | - | -targetLocales | en-US | Target locale of the translation. | - | -translationId | MyTranslateVideo1FromZhCNToEnUS2024050601 | Translation ID. | - | -iterationId | MyFirstIteration2024050601 | Iteration ID. | - | -videoFileAzureBlobUrl | | Please proivde video file URL, with or without SAS, which is hosted in an Azure storage blob. | - | -webvttFileAzureBlobUrl | | Please provide the WebVTT file URL, with or without SAS, which is hosted in an Azure storage blob. It is optional for the first iteration of the translation but required from the second iteration. | - | -webvttFileKind | TargetLocaleSubtitle/SourceLocaleSubtitle/MetadataJson | Please specify the kind of WebVTT file with a value of TargetLocaleSubtitle, SourceLocaleSubtitle, or MetadataJson. | - | -subtitleMaxCharCountPerSegment | 100 | Please specify the maximum display character count per segment for the subtitles. | - | -speakerCount | 1 | Please specify the speaker count of the video. | - | -exportSubtitleInVideo | false | Please indicate whether to export subtitles in the video. | + | Argument | Is Required | Supported Values Sample | Description | + | -------- | -------- | ---------------- | ----------- | + | --region | True | eastus | Provide the region of the API request. | + | --subscriptionKey | True | | Provide your speech resource key. | + | --apiVersion | True | 2024-05-20-preview | Provide the version of the API request. | + | --voiceKind | True | PlatformVoice/PersonalVoice | Synthesize TTS for the translated target video using either PlatformVoice or PersonalVoice. | + | --sourceLocale | True | en-US | The locale of the input video file. | + | --targetLocales | True | en-US | Target locale of the translation. | + | --translationId | True | MyTranslateVideo1FromZhCNToEnUS2024050601 | Translation ID. | + | --iterationId | True | MyFirstIteration2024050601 | Iteration ID. | + | --videoFileAzureBlobUrl | True | URL | Please proivde video file URL, with or without SAS, which is hosted in an Azure storage blob. | + | --webvttFileAzureBlobUrl | False | URL | Please provide the WebVTT file URL, with or without SAS, which is hosted in an Azure storage blob. It is optional for the first iteration of the translation but required from the second iteration. | + | --webvttFileKind | False | TargetLocaleSubtitle/SourceLocaleSubtitle/MetadataJson | Please specify the kind of WebVTT file with a value of TargetLocaleSubtitle, SourceLocaleSubtitle, or MetadataJson. | + | --subtitleMaxCharCountPerSegment | False | 100 | Please specify the maximum display character count per segment for the subtitles. | + | --speakerCount | False | 1 | Please specify the speaker count of the video. | + | --exportSubtitleInVideo | False | False | Please indicate whether to export subtitles in the video. | + +# Argument definitions +## Supported regions + https://learn.microsoft.com/azure/ai-services/speech-service/regions + + Use region identifier for the region argument. + +## Supported API versions: +* 2024-05-20-preview + +## Supported VoiceKind +* PlatformVoice +* PersonalVoice # Best practice - ## Escape char for argument -videoFileAzureBlobUrl and -webvttFileAzureBlobUrl +## Escape char for URL arguments in Windows + For arguments: --videoFileAzureBlobUrl and --webvttFileAzureBlobUrl If you run a client sample tool in a Windows shell and there is an & in the URL arguments (for example, a SAS token in an Azure blob URL), the & needs to be converted to ^& to escape it. For example, if the actual URL for the argument videoFileAzureBlobUrl is https://a/b?c&d, then when you run the command in the Windows shell, you need to run the command like this: - -videoFileAzureBlobUrl "https://a/b?c^&d" + --videoFileAzureBlobUrl "https://a/b?c^&d" - ## How to retry? +## How to retry? If you initiate a command to create a translation or iteration job and subsequently restart Windows, the job will continue to run on the server side. To check the status of the translation/iteration job, you can use the query translation/iteration tool command or the API, providing the specific translation/iteration ID. \ No newline at end of file diff --git a/samples/video-translation/python/readme.md b/samples/video-translation/python/readme.md index 3f4c34c91..f9e78ae27 100644 --- a/samples/video-translation/python/readme.md +++ b/samples/video-translation/python/readme.md @@ -33,11 +33,11 @@ | Files | Description | | --- | --- | | [main.py](main.py) | client tool main definition | -| [video_translation_client.py](microsoft_video_translation_client\video_translation_client.py) | video translation client definition | -| [video_translation_dataclass.py](microsoft_video_translation_client\video_translation_dataclass.py) | video translation data contract definition | -| [video_translation_enum.py](microsoft_video_translation_client\video_translation_enum.py) | video translation enum definition | -| [video_translation_const.py](microsoft_video_translation_client\video_translation_const.py) | video translation constant definition | -| [video_translation_util.py](microsoft_video_translation_client\video_translation_util.py) | video translation utility function definition | +| [video_translation_client.py](microsoft_video_translation_client/video_translation_client.py) | video translation client definition | +| [video_translation_dataclass.py](microsoft_video_translation_client/video_translation_dataclass.py) | video translation data contract definition | +| [video_translation_enum.py](microsoft_video_translation_client/video_translation_enum.py) | video translation enum definition | +| [video_translation_const.py](microsoft_video_translation_client/video_translation_const.py) | video translation constant definition | +| [video_translation_util.py](microsoft_video_translation_client/video_translation_util.py) | video translation utility function definition | # Usage for command line tool: ## Usage @@ -65,7 +65,7 @@ Run main.py with command in below pattern: | request_get_iteration_api | Request get iteration API | ## HTTP client library -Video translation client is defined as class VideoTranslationClient in file [video_translation_client.py](microsoft_video_translation_client\video_translation_client.py) +Video translation client is defined as class VideoTranslationClient in file [video_translation_client.py](microsoft_video_translation_client/video_translation_client.py) ### Function definitions: | Function | Description | | --- | --- |