Telegram бот и использование Google Cloud Vision
Всем привет! Недавно я уже писал статью про интеграцию своего бота с IBM Watson, а в этой статье рассмотрю интеграцию с Google Cloud Vision для распознавания котиков и более подробно опишу внутренности своего бота.
Небольшая предыстория:
Мой бот вполне успешно работал пару месяцев с использованием распознавания IBM Watson, однако затем на хабре вышла статья про google cloud vision и оказалось, что Google распознает изображения лучше, чем IBM. В тот же день я зарегистрировался в консоли разработчика Google cloud platform и начал переписывать блок модерации котиков в своем боте.
Немного поискав, я нашел подходящий пример на C# на гитхабе GoogleCloudPlatform. Я поменял аутентификацию из примера и сделал ее из json файла с private key, который взял в разделе «сервисные аккаунты» консоли.
private VisionService service;
private string _JsonPath = @"C:\BOTS\fcatsbot\json.json";
private VisionService CreateAuthorizedClient(string JsonPath)
{
GoogleCredential credential =
GoogleCredential.FromStream(new FileStream(JsonPath, FileMode.Open));
// Inject the Cloud Vision scopes
if (credential.IsCreateScopedRequired)
{
credential = credential.CreateScoped(new[]
{
VisionService.Scope.CloudPlatform
});
}
var res = new VisionService(new BaseClientService.Initializer
{
HttpClientInitializer = credential,
GZipEnabled = false
});
return res;
}
Далее я переделал модерацию изображений (label detection). В примере на гитхабе DetectLabels работает с файлом, а мне нужно было работать с ссылкой, которую я получал с серверов Telegram, чтобы не хранить у себя файлы изображений. Я сохраняю в базе только file_id, что дает неплохой прирост скорости работы.
private async Task> DetectLabels(
VisionService vision, string imageUrl)
{
// Convert image to Base64 encoded for JSON ASCII text based request
MemoryStream ms = new MemoryStream();
using (var client = new HttpClient())
{
Stream imageBytes = await client.GetStreamAsync(imageUrl);
imageBytes.CopyTo(ms);
}
byte[] imageArray = ms.ToArray();
string imageContent = Convert.ToBase64String(imageArray);
// Post label detection request to the Vision API
// [START construct_request]
var responses = vision.Images.Annotate(
new BatchAnnotateImagesRequest()
{
Requests = new[] {
new AnnotateImageRequest() {
Features = new []
{ new Feature()
{ Type =
"LABEL_DETECTION"}
},
Image = new Image() { Content = imageContent }
}
}
}).Execute();
ms.Dispose();
return responses.Responses;
}
Затем я ищу в Responses есть ли label с описанием котика, с оценкой более 0.6, и таким образом, определяю есть ли котик в переданной боту картинке:
foreach (var response in responses.Responses)
{
foreach (var label in response.LabelAnnotations)
{
double _score = label.Score == null ? 0 : Convert.ToDouble(label.Score.Value);
var class = label.Description.Trim();
if (class .Contains("kitten") || class .Contains("cat") ) && (_score > 0.60))
{
HasCatOrKittenClass = true;//moderation OK
}
}
}
Вот код работы с API Telegram для получения ссылки на изображение из file_id, я использовал библиотеку на C# telegram bot:
var file = await MainParams.TGBot.GetFileAsync(fileid);
var file_path = file.FilePath;
var urlImage = "https://api.telegram.org/file/bot" + MainParams.bot_token + "/" + file_path;
А когда я отправляю изображение пользователю с помощью sendPhoto, я просто передаю сохраненный file_id вторым параметром.
Таким образом, получается что когда пользователь присылает свое фото котика на модерацию (или использует для этого thecatapi.com), я сохраняю в базе только file_id и в дальнейшем использую его для получения ссылки на картинку на серверах Telegram и для отправки пользователям с помощью sendPhoto. А распознавание изображений с помощью Google cloud vision работает более точно, чем у IBM Watson