From e5ef1b3cc5f0c904d619de55a7c7ffcd6cc96afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timofei=20J=C3=A4=C3=A4ger?= <41389318+Panuchi@users.noreply.github.com> Date: Thu, 20 Apr 2023 15:09:48 +0300 Subject: [PATCH] =?UTF-8?q?#1499=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D1=8F=D0=B5=D1=82=20=D0=BC=D0=B5=D1=82=D0=BE=D0=B4=D1=8B=20Asr?= =?UTF-8?q?=20(#1506)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Исправляет параметры метода Messages.Send * Добавляет метод Asr.CheckStatus * Добавляет метод Asr.GetUploadUrl * Добавляет метод Asr.Process --- VkNet.Tests/Categories/Asr/AsrCategoryTest.cs | 58 +++++++++++++++++++ .../TestData/Categories/Asr/CheckStatus.json | 7 +++ .../TestData/Categories/Asr/GetUploadUrl.json | 5 ++ .../TestData/Categories/Asr/Process.json | 5 ++ .../Category/Async/IAsrCategoryAsync.cs | 57 ++++++++++++++++++ VkNet/Abstractions/Category/IAsrCategory.cs | 17 ++++++ VkNet/Abstractions/Core/IVkApiCategories.cs | 5 ++ VkNet/Categories/AsrCategory.cs | 46 +++++++++++++++ VkNet/Categories/Async/AsrCategoryAsync.cs | 27 +++++++++ VkNet/Enums/StringEnums/AsrProcessModel.cs | 23 ++++++++ VkNet/Enums/StringEnums/AsrStatus.cs | 40 +++++++++++++ VkNet/Model/Results/Asr/AudioRecordingTask.cs | 30 ++++++++++ VkNet/Model/Results/Asr/TaskIdResult.cs | 17 ++++++ VkNet/Model/Results/Asr/UploadUrlResult.cs | 17 ++++++ VkNet/VkApi.cs | 5 ++ 15 files changed, 359 insertions(+) create mode 100644 VkNet.Tests/Categories/Asr/AsrCategoryTest.cs create mode 100644 VkNet.Tests/TestData/Categories/Asr/CheckStatus.json create mode 100644 VkNet.Tests/TestData/Categories/Asr/GetUploadUrl.json create mode 100644 VkNet.Tests/TestData/Categories/Asr/Process.json create mode 100644 VkNet/Abstractions/Category/Async/IAsrCategoryAsync.cs create mode 100644 VkNet/Abstractions/Category/IAsrCategory.cs create mode 100644 VkNet/Categories/AsrCategory.cs create mode 100644 VkNet/Categories/Async/AsrCategoryAsync.cs create mode 100644 VkNet/Enums/StringEnums/AsrProcessModel.cs create mode 100644 VkNet/Enums/StringEnums/AsrStatus.cs create mode 100644 VkNet/Model/Results/Asr/AudioRecordingTask.cs create mode 100644 VkNet/Model/Results/Asr/TaskIdResult.cs create mode 100644 VkNet/Model/Results/Asr/UploadUrlResult.cs diff --git a/VkNet.Tests/Categories/Asr/AsrCategoryTest.cs b/VkNet.Tests/Categories/Asr/AsrCategoryTest.cs new file mode 100644 index 000000000..4826e1b8e --- /dev/null +++ b/VkNet.Tests/Categories/Asr/AsrCategoryTest.cs @@ -0,0 +1,58 @@ +using System; +using FluentAssertions; +using VkNet.Enums.StringEnums; +using VkNet.Tests.Infrastructure; +using Xunit; + +namespace VkNet.Tests.Categories.Asr; + +public class AsrCategoryTest : CategoryBaseTest +{ + protected override string Folder => "Asr"; + + [Fact] + public void CheckStatus() + { + Url = "https://api.vk.com/method/asr.checkStatus"; + + ReadCategoryJsonPath(nameof(CheckStatus)); + + var result = Api.Asr.CheckStatus("7ee0fa8e-64ac-4391-af7a-5c98a6330866"); + + result.Id.Should() + .Be("7ee0fa8e-64ac-4391-af7a-5c98a6330866"); + + result.Text.Should() + .Be("Это тестовая запись для сервиса распознавания речи ВКонтакте."); + + result.Status.Should() + .Be(AsrStatus.Finished); + } + + [Fact] + public void GetUploadUrl() + { + Url = "https://api.vk.com/method/asr.getUploadUrl"; + + ReadCategoryJsonPath(nameof(GetUploadUrl)); + + var result = Api.Asr.GetUploadUrl(); + + result.UploadUrl.Should() + .Be(new Uri( + "https://pu.vk.com/gu/speech/v2/upload?token=eyJ0e13iOiJKV1QiLCJhbGmdOiJIUzI1NiJ9.eyqlmAQiOjE2NjM1OTAzNDYsInZrX3VzZXJfaWQiOjgxNDI3MDksInZrX2FwcF9pZCI6ODE0MjcwOSwidmtfdXBsb2FkX3R5cGUiOiJzcGVlY2gifQ.9PStNUU8cf-rlFdPhM5hKQ2xSjhbxzxy7SRKYHvXC_M")); + } + + [Fact] + public void Process() + { + Url = "https://api.vk.com/method/asr.process"; + + ReadCategoryJsonPath(nameof(Process)); + + var result = Api.Asr.Process("asd", AsrProcessModel.Neutral); + + result.TaskId.Should() + .Be("7ee0fa8e-64ac-4391-af7a-5c98a6330866"); + } +} \ No newline at end of file diff --git a/VkNet.Tests/TestData/Categories/Asr/CheckStatus.json b/VkNet.Tests/TestData/Categories/Asr/CheckStatus.json new file mode 100644 index 000000000..87b5c6940 --- /dev/null +++ b/VkNet.Tests/TestData/Categories/Asr/CheckStatus.json @@ -0,0 +1,7 @@ +{ + "response": { + "id": "7ee0fa8e-64ac-4391-af7a-5c98a6330866", + "status": "finished", + "text": "Это тестовая запись для сервиса распознавания речи ВКонтакте." + } +} \ No newline at end of file diff --git a/VkNet.Tests/TestData/Categories/Asr/GetUploadUrl.json b/VkNet.Tests/TestData/Categories/Asr/GetUploadUrl.json new file mode 100644 index 000000000..58be8d8fa --- /dev/null +++ b/VkNet.Tests/TestData/Categories/Asr/GetUploadUrl.json @@ -0,0 +1,5 @@ +{ + "response":{ + "upload_url": "https://pu.vk.com/gu/speech/v2/upload?token=eyJ0e13iOiJKV1QiLCJhbGmdOiJIUzI1NiJ9.eyqlmAQiOjE2NjM1OTAzNDYsInZrX3VzZXJfaWQiOjgxNDI3MDksInZrX2FwcF9pZCI6ODE0MjcwOSwidmtfdXBsb2FkX3R5cGUiOiJzcGVlY2gifQ.9PStNUU8cf-rlFdPhM5hKQ2xSjhbxzxy7SRKYHvXC_M" + } +} \ No newline at end of file diff --git a/VkNet.Tests/TestData/Categories/Asr/Process.json b/VkNet.Tests/TestData/Categories/Asr/Process.json new file mode 100644 index 000000000..e8b298ff0 --- /dev/null +++ b/VkNet.Tests/TestData/Categories/Asr/Process.json @@ -0,0 +1,5 @@ +{ + "response":{ + "task_id": "7ee0fa8e-64ac-4391-af7a-5c98a6330866" + } +} \ No newline at end of file diff --git a/VkNet/Abstractions/Category/Async/IAsrCategoryAsync.cs b/VkNet/Abstractions/Category/Async/IAsrCategoryAsync.cs new file mode 100644 index 000000000..88c027ab5 --- /dev/null +++ b/VkNet/Abstractions/Category/Async/IAsrCategoryAsync.cs @@ -0,0 +1,57 @@ +using System.Threading; +using System.Threading.Tasks; +using VkNet.Enums.StringEnums; +using VkNet.Model.Results.Asr; + +namespace VkNet.Abstractions; + +/// +/// Методы для работы с ASR +/// +public interface IAsrCategoryAsync +{ + /// + /// Метод проверяет статус задачи на обработку аудиозаписи и возвращает текстовую расшифровку аудиозаписи + /// + /// + /// Идентификатор созданной задачи на обработку аудиозаписи в формате UUID. + /// + /// Токен отмены + /// + /// Возвращает объект задачи на обработку аудиозаписи. + /// + /// + /// Страница документации ВКонтакте https://dev.vk.com/method/asr.checkStatus + /// + public Task CheckStatusAsync(string taskId, + CancellationToken token = default); + + /// + /// Метод возвращает ссылку на адрес сервера для загрузки аудиозаписи. + /// Обратите внимание! Ссылка доступна в течение 24 часов. + /// + /// Токен отмены + /// + /// Возвращает параметр — ссылку на адрес сервера для загрузки аудиозаписи + /// + /// + /// Страница документации ВКонтакте https://dev.vk.com/method/asr.getUploadUrl + /// + public Task GetUploadUrlAsync(CancellationToken token = default); + + /// + /// Метод выполняет распознавание речи из загруженного файла аудиозаписи. + /// + /// Модель распознавания речи, которую нужно использовать + /// Токен отмены + /// JSON-ответ из запроса на отправку файла аудиозаписи на адрес сервера загрузки. + /// + /// Возвращает параметр — идентификатор созданной задачи на обработку аудиозаписи в формате UUID + /// + /// + /// Страница документации ВКонтакте https://dev.vk.com/method/asr.process + /// + public Task ProcessAsync(string audio, + AsrProcessModel model, + CancellationToken token = default); +} \ No newline at end of file diff --git a/VkNet/Abstractions/Category/IAsrCategory.cs b/VkNet/Abstractions/Category/IAsrCategory.cs new file mode 100644 index 000000000..e5077adaa --- /dev/null +++ b/VkNet/Abstractions/Category/IAsrCategory.cs @@ -0,0 +1,17 @@ +using VkNet.Enums.StringEnums; +using VkNet.Model.Results.Asr; + +namespace VkNet.Abstractions; + +/// +public interface IAsrCategory : IAsrCategoryAsync +{ + /// + AudioRecordingTask CheckStatus(string taskId); + + /// + UploadUrlResult GetUploadUrl(); + + /// + TaskIdResult Process(string audio, AsrProcessModel model); +} \ No newline at end of file diff --git a/VkNet/Abstractions/Core/IVkApiCategories.cs b/VkNet/Abstractions/Core/IVkApiCategories.cs index ad3fa46b1..3b4e6e9db 100644 --- a/VkNet/Abstractions/Core/IVkApiCategories.cs +++ b/VkNet/Abstractions/Core/IVkApiCategories.cs @@ -223,4 +223,9 @@ public interface IVkApiCategories /// Donut /// IDownloadedGamesCategory DownloadedGames { get; } + + /// + /// Asr + /// + IAsrCategory Asr { get; } } \ No newline at end of file diff --git a/VkNet/Categories/AsrCategory.cs b/VkNet/Categories/AsrCategory.cs new file mode 100644 index 000000000..ba3070693 --- /dev/null +++ b/VkNet/Categories/AsrCategory.cs @@ -0,0 +1,46 @@ +using VkNet.Abstractions; +using VkNet.Enums.StringEnums; +using VkNet.Model.Results.Asr; +using VkNet.Utils; + +namespace VkNet.Categories; + +/// +public partial class AsrCategory : IAsrCategory +{ + /// + /// API. + /// + private readonly IVkApiInvoke _vk; + + /// + /// api vk.com + /// + /// API. + public AsrCategory(IVkApiInvoke vk) => _vk = vk; + + /// + public AudioRecordingTask CheckStatus(string taskId) => _vk.Call("asr.checkStatus", + new() + { + { + "task_id", taskId + } + }); + + /// + public UploadUrlResult GetUploadUrl() => _vk.Call("asr.getUploadUrl", + VkParameters.Empty); + + /// + public TaskIdResult Process(string audio, AsrProcessModel model) => _vk.Call("asr.process", + new() + { + { + "audio", audio + }, + { + "model", model + } + }); +} \ No newline at end of file diff --git a/VkNet/Categories/Async/AsrCategoryAsync.cs b/VkNet/Categories/Async/AsrCategoryAsync.cs new file mode 100644 index 000000000..a5695c518 --- /dev/null +++ b/VkNet/Categories/Async/AsrCategoryAsync.cs @@ -0,0 +1,27 @@ +using System.Threading; +using System.Threading.Tasks; +using VkNet.Enums.StringEnums; +using VkNet.Model.Results.Asr; +using VkNet.Utils; + +namespace VkNet.Categories; + +/// +public partial class AsrCategory +{ + /// + public Task CheckStatusAsync(string taskId, + CancellationToken token = default) => + TypeHelper.TryInvokeMethodAsync(() => + CheckStatus(taskId), token); + + /// + public Task GetUploadUrlAsync(CancellationToken token = default) => + TypeHelper.TryInvokeMethodAsync(GetUploadUrl, token); + + /// + public Task ProcessAsync(string audio, AsrProcessModel model, CancellationToken token = default) => + TypeHelper.TryInvokeMethodAsync(() => + Process(audio, model), token); + +} \ No newline at end of file diff --git a/VkNet/Enums/StringEnums/AsrProcessModel.cs b/VkNet/Enums/StringEnums/AsrProcessModel.cs new file mode 100644 index 000000000..7238101ce --- /dev/null +++ b/VkNet/Enums/StringEnums/AsrProcessModel.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +namespace VkNet.Enums.StringEnums; + +/// +/// Модель распознавания речи, которую нужно использовать +/// +[StringEnum] +[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))] +public enum AsrProcessModel +{ + /// + /// Распознавание разборчивой речи, как в интервью или телешоу. + /// + Neutral, + + /// + /// Распознавание речи со сленгом и ненормативной лексикой. + /// + Spontaneous +} \ No newline at end of file diff --git a/VkNet/Enums/StringEnums/AsrStatus.cs b/VkNet/Enums/StringEnums/AsrStatus.cs new file mode 100644 index 000000000..72ea4979b --- /dev/null +++ b/VkNet/Enums/StringEnums/AsrStatus.cs @@ -0,0 +1,40 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Newtonsoft.Json.Serialization; + +namespace VkNet.Enums.StringEnums; + +/// +/// Права пользователя в рекламном кабинете. +/// +[StringEnum] +[JsonConverter(typeof(StringEnumConverter), typeof(SnakeCaseNamingStrategy))] +public enum AsrStatus +{ + /// + /// Аудиозапись обрабатывается + /// + Processing, + + /// + /// Обработка аудиозаписи закончена. + /// + Finished, + + /// + /// Внутренние ошибки сервиса распознавания речи ВКонтакте. + /// + InternalError, + + /// + /// Ошибка перекодирования аудиозаписи во внутренний формат. + /// Попробуйте загрузить аудиозапись в другом поддерживаемом формате. + /// + TranscodingError , + + /// + /// Ошибка распознавания речи, сложности в распознавании. + /// Попробуйте говорить чётче или снизить фоновые шумы. + /// + RecognitionError +} \ No newline at end of file diff --git a/VkNet/Model/Results/Asr/AudioRecordingTask.cs b/VkNet/Model/Results/Asr/AudioRecordingTask.cs new file mode 100644 index 000000000..5ec000da1 --- /dev/null +++ b/VkNet/Model/Results/Asr/AudioRecordingTask.cs @@ -0,0 +1,30 @@ +using System; +using Newtonsoft.Json; +using VkNet.Enums.StringEnums; + +namespace VkNet.Model.Results.Asr; + +/// +/// Объект задачи на обработку аудиозаписи +/// +[Serializable] +public class AudioRecordingTask +{ + /// + /// Идентификатор созданной задачи на обработку аудиозаписи в формате UUID. + /// + [JsonProperty("id")] + public string Id { get; set; } + + /// + /// Статус задачи на обработку аудиозаписи. + /// + [JsonProperty("status")] + public AsrStatus Status { get; set; } + + /// + /// Расшифровка текста. Имеет значение, если параметр status имеет значение finished. + /// + [JsonProperty("text")] + public string Text { get; set; } +} \ No newline at end of file diff --git a/VkNet/Model/Results/Asr/TaskIdResult.cs b/VkNet/Model/Results/Asr/TaskIdResult.cs new file mode 100644 index 000000000..534f2027a --- /dev/null +++ b/VkNet/Model/Results/Asr/TaskIdResult.cs @@ -0,0 +1,17 @@ +using System; +using Newtonsoft.Json; + +namespace VkNet.Model.Results.Asr; + +/// +/// Объект TaskId +/// +[Serializable] +public class TaskIdResult +{ + /// + /// Идентификатор созданной задачи на обработку аудиозаписи в формате UUID + /// + [JsonProperty("task_id")] + public string TaskId { get; set; } +} \ No newline at end of file diff --git a/VkNet/Model/Results/Asr/UploadUrlResult.cs b/VkNet/Model/Results/Asr/UploadUrlResult.cs new file mode 100644 index 000000000..af8d61dbf --- /dev/null +++ b/VkNet/Model/Results/Asr/UploadUrlResult.cs @@ -0,0 +1,17 @@ +using System; +using Newtonsoft.Json; + +namespace VkNet.Model.Results.Asr; + +/// +/// Объект UploadUrl +/// +[Serializable] +public class UploadUrlResult +{ + /// + /// Ссылка на адрес сервера для загрузки аудиозаписи + /// + [JsonProperty("upload_url")] + public Uri UploadUrl { get; set; } +} \ No newline at end of file diff --git a/VkNet/VkApi.cs b/VkNet/VkApi.cs index c02061b56..2d91960b9 100644 --- a/VkNet/VkApi.cs +++ b/VkNet/VkApi.cs @@ -732,6 +732,9 @@ public int MaxCaptchaRecognitionCount /// public IDownloadedGamesCategory DownloadedGames { get; set; } + /// + public IAsrCategory Asr { get; set; } + #endregion #region private @@ -998,6 +1001,8 @@ private void Initialization(IServiceProvider serviceProvider) Podcasts = new PodcastsCategory(this); Donut = new DonutCategory(this); DownloadedGames = new DownloadedGamesCategory(this); + Asr = new AsrCategory(this); + RequestsPerSecond = 3;