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;