Вступление
Совсем недавно я начал работу над новым проектом, который включал в себя работу с уже достаточно известным сервисом (AI) от Google — DialogFlow. Суть заключалась в том, что у нас был бот (Telegram) который работал с API нескольких сайтов, а сам же DialogFlow помогал нам структурировать само общение с человеком, для чего он в принципе и создавался. Нужно сказать, что статья предназначена для людей, которые только начали знакомство с сервисом или уже имеют небольшой опыт, так далее возможны термины: Intent, Context, Action, Event ну и то ради чего мы и собрались — Entities. Надеюсь, что статья будет полезна тем, кто немного не понял как именно через код можно проделывать CRUD операции с Entities.
Entities в DialogFlow
В DialogFlow Entities представляют собой некие сущности, которые состоят из ReferenceValue и Synonyms. Что-то похожее на ключ-значение, только с той разницей, что синонимов может быть много, и чем их больше — тем лучше, поскольку это «упрощает боту жизнь» и ему легче понять о каком значении идет сейчас речь, а поставленная галочка на Fuzzy matching поможет боту еще и понимать о чём идет речь, даже если вы упустили одну букву или другой символ. Выглядит это примерно так:
Москва — москва, Москва, Мсква…
Заканчивая короткий экскурс, хотел бы добавить, что именно с Entity происходит очень много всякой возни. Я конечно же не уменьшаю значение интентов и так далее, но факт остается фактом.
EntityTypes
Вот тут и был для меня первый, хоть и небольшой, подводный камень. Ведь в документации есть методы для работы с Entity, а есть для работы с EntityType — что из них что?
На самом деле всё не так и сложно, просто путаница возникает из-за того, что в самом DialogFlow вкладка с EntityTypes называется Entities:
EntityType:
Entitie:
Хотя в самом DialogFlow считается, что есть Entity и в ней есть Entries (т.е. Сущность и записи в ней).
Перейдём дальше.
Можно создать EntityType вручную прямо на DialoFlow, но я покажу, как это возможно сделать через код (ведь потом, чтобы создавать Entities нам нужно будет знать в каком именно EntityType это делать).
Сперва подключим NuGet пакет Google.Cloud.Dialogflow.V2. На момент написания статьи, была установлена версия 1.1.0:
Создадим сперва класc и назовём его EntityTypeManagement в котором будут основные операции:
using Google.Api.Gax;
using Google.Cloud.Dialogflow.V2;
public class EntityTypeManagement
{
//Create - создание нового EntityType по типу Test1 (на картинке выше)
//projectId - Id вашего агента с DialogFlow
//displayName - имя которые вы хотите задать для нового
public async Task Create(string projectId, string displayName, EntityType.Types.Kind kind =
EntityType.Types.Kind.Map)
{
var client = await EntityTypesClient.CreateAsync();
var entityType = new EntityType();
entityType.DisplayName = displayName;
entityType.Kind = kind;
var createdEntityType = client.CreateEntityType(
parent: new ProjectAgentName(projectId),
entityType: entityType
);
Console.WriteLine($"Created EntityType: {createdEntityType.Name}");
}
//List - получение всех EntityTypes от вашего агента
//projectId - Id вашего агента с DialogFlow
public async Task<PagedEnumerable<ListEntityTypesResponse,EntityType>> List(string projectId)
{
var client = await EntityTypesClient.CreateAsync();
var response = client.ListEntityTypes(
parent: new ProjectAgentName(projectId)
);
return response;
}
//GetEntityTypeId - получение EntityType за именем
//projectId - Id вашего агента с DialogFlow
//targetEventTypeName - имя EntityType, которое вы ищите
public async Task<string> GetEntityTypeId(string projectId,string targetEventTypeName)
{
var client = await EntityTypesClient.CreateAsync();
var response = client.ListEntityTypes(
parent: new ProjectAgentName(projectId)
);
string id = response.Where(x => x.DisplayName == targetEventTypeName).FirstOrDefault().Name;
string returningId = id.Replace($"projects/{projectId}/agent/entityTypes/", "");
return returningId;
}
//Delete и BatchDelete удаление одного и нескольких сразу EntityType
//Удаление происходит по entityTypeId
public async Task Delete(string projectId, string entityTypeId)
{
var client = await EntityTypesClient.CreateAsync();
client.DeleteEntityType(new EntityTypeName(projectId, entityTypeId: entityTypeId));
Console.WriteLine($"Deleted EntityType: {entityTypeId}");
}
public async Task BatchDelete(string projectId, IEnumerable<string> entityTypeIds)
{
var client = await EntityTypesClient.CreateAsync();
var entityTypeNames = entityTypeIds.Select(
id => new EntityTypeName(projectId, id).ToString());
client.BatchDeleteEntityTypes(new ProjectAgentName(projectId),
entityTypeNames);
}
}
Тут сразу нужно сказать, что функции Update нет лишь потому, что Create уже выполняет её функцию.
Теперь когда мы имеем базовые методы для работы с EntityTypes перейдём к Entity и сразу же создадим класc EntityManagement:
public class EntityManagement
{
using Google.Cloud.Dialogflow.V2;
//Create - создание только одной Entity
//entityTypeId - Id EntityType в котором мы хотим создать Entity
//entityValue - ReferenceValue для Entity
// synonyms - массив синонимов для Entity
public async Task Create(string projectId,
string entityTypeId,
string entityValue,
string[] synonyms)
{
var client = await EntityTypesClient.CreateAsync();
var entity = new EntityType.Types.Entity() { Value = entityValue};
entity.Synonyms.AddRange(synonyms);
var operation = await client.BatchCreateEntitiesAsync(
parent: new EntityTypeName(projectId, entityTypeId),
entities: new[] { entity }
);
operation.PollUntilCompleted();
}
//CreateMany - Создание многих Entities
//entityTypeId - Id EntityType в котором мы хотим создать Entity
//entities - коллекция Entities для создания
public async Task CreateMany(string projectId,string entityTypeId, IEnumerable<Entity> entities)
{
var client = await EntityTypesClient.CreateAsync();
List<EntityType.Types.Entity> results = new List<EntityType.Types.Entity>();
foreach (var item in entities)
{
var entity = new EntityType.Types.Entity() { Value = item.value };
entity.Synonyms.AddRange(item.synonyms);
results.Add(entity);
}
var operation = await client.BatchCreateEntitiesAsync(
parent: new EntityTypeName(projectId, entityTypeId),
entities: results.ToArray());
operation.PollUntilCompleted();
}
//Delete - для удаления одной Entity, но если "string entityValue" заменить на
//string[] entityValue и в коде просто присвоить entityValues: entityValue
//то будет для нескольких сразу.
public async Task Delete(string projectId, string entityTypeId, string entityValue)
{
var client = await EntityTypesClient.CreateAsync();
var operation = await client.BatchDeleteEntitiesAsync(
parent: new EntityTypeName(projectId, entityTypeId),
entityValues: new[] { entityValue }
);
Console.WriteLine("Waiting for the entity deletion operation to complete.");
operation.PollUntilCompleted();
Console.WriteLine($"Deleted Entity: {entityValue}");
}
//List - Получение всех Entities с EntityType
public async Task<List<Entity>> List(string projectId, string entityTypeId)
{
var client = await EntityTypesClient.CreateAsync();
var entityType = await client.GetEntityTypeAsync(new EntityTypeName(
projectId, entityTypeId
));
List<Entity> EntitiesList = new List<Entity>();
foreach (var entity in entityType.Entities)
{
List<string> Synonyms = new List<string>();
foreach (var item in entity.Synonyms)
{
Synonyms.Add(item);
}
EntitiesList.Add(new Entity { value = entity.Value, synonyms = Synonyms.ToArray() });
Synonyms = null;
}
return EntitiesList;
}
}
Добавим нашу модель, которая будет представлять Entity:
public class Entity
{
public string value { get; set; }
public string[] synonyms { get; set; }
}
Готово, все базовые функции CRUD готовы. Опять-таки, возвращаясь к Update, ее можно отдельно реализовать, но она попросту не нужна, так как Create работает и как Update тоже.
Примеры достаточно просты и, нужно согласиться, тут есть таки «хардкод», но надеюсь статья пригодится тем, кто, как и я, не мог понять как же правильно проделывать CRUD операции через код.
static void Main(string[] args)
{
EntityTypesManagement entityTypesManagement = new EntityTypesManagement();
EntityManagement entityManagement = new EntityManagement();
string ProjectId = "Your Project`s id";
string EntityName = "Your EntityName";
var entityId = await entityTypesManagement.GetEntityTypeId(ProjectId, EntityName);
Entity entity = new Entity{value = "1", synonyms = new[]{"1","1"}};
/*await*/ entityManagement.Create(ProjectId,entityId,entity);
}
somebody4
Можно сделать export из DialogFlow потом с помощью T4 правильно нагенерить все классы которые требуется без геморроя.
Так делать чревато боком. Вы вводите собственную версию наименований. У гугла это называется DisplayName вы называете targetEventTypeName. человек который знаком с DialogFlow API будет теряться, что это такое.yanchak01 Автор
Да, но это был мой первый опыт, которым я хотел поделиться, чтобы, возможно, кому-то помочь.
А вот если говорить о targerEventTypeName, то возможно вы и правы, просто я хотел обозначить как-то, что это именно имя целевого EventType.
И был бы признателен вам за ссылку на пост, или статью, или другой ресур где есть пример того, о чём вы говорите.