Skip to content

Commit fce20af

Browse files
committed
Added handling for Instagram
1 parent 37c6f23 commit fce20af

File tree

2 files changed

+155
-100
lines changed

2 files changed

+155
-100
lines changed

Fritz.Chatbot/Commands/HyperlinkCommand.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public bool CanExecute(string userName, string fullCommandText)
2121
{
2222

2323
// Match the regular expression pattern against a text string.
24-
return reCheck.IsMatch(fullCommandText);
24+
return !ImageDescriptorCommand._InstagramCheck.IsMatch(fullCommandText) && reCheck.IsMatch(fullCommandText);
2525

2626
}
2727

Fritz.Chatbot/Commands/ImageDescriptorCommand.cs

Lines changed: 154 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -11,144 +11,199 @@
1111
using Fritz.StreamLib.Core;
1212
using Microsoft.Extensions.Configuration;
1313
using Newtonsoft.Json;
14+
using Newtonsoft.Json.Linq;
1415

1516
namespace Fritz.Chatbot.Commands
1617
{
17-
public class ImageDescriptorCommand : IExtendedCommand
18-
{
19-
public string Name => "Image";
20-
public string Description => "Inspect images and report to the chat room what they contain using Vision API";
21-
public int Order => 10;
22-
public bool Final => false;
23-
24-
private readonly string _AzureUrl;
25-
private readonly string _AzureApiKey;
26-
private string ImageUrl;
27-
private string v1;
28-
private string v2;
29-
30-
public TimeSpan? Cooldown => null;
31-
32-
private static readonly Regex _UrlCheck = new Regex(@"http(s)?:?(\/\/[^""']*\.(?:png|jpg|jpeg|gif))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
33-
private readonly IHttpClientFactory _ClientFactory;
34-
35-
public ImageDescriptorCommand(IConfiguration config, IHttpClientFactory clientFactory) : this(config["FritzBot:VisionApiBaseUrl"], config["FritzBot:VisionApiKey"])
18+
public class ImageDescriptorCommand : IExtendedCommand
3619
{
37-
_ClientFactory = clientFactory;
38-
}
20+
public string Name => "Image";
21+
public string Description => "Inspect images and report to the chat room what they contain using Vision API";
22+
public int Order => 10;
23+
public bool Final => true;
24+
25+
private readonly string _AzureUrl;
26+
private readonly string _AzureApiKey;
27+
private string ImageUrl;
28+
private (string owner, string) _InstagramInfo;
29+
private ImageProviders Provider = ImageProviders.None;
30+
private string v1;
31+
private string v2;
32+
33+
public TimeSpan? Cooldown => null;
34+
35+
private static readonly Regex _UrlCheck = new Regex(@"http(s)?:?(\/\/[^""']*\.(?:png|jpg|jpeg|gif))", RegexOptions.IgnoreCase | RegexOptions.Compiled);
36+
internal static readonly Regex _InstagramCheck = new Regex(@"(?<InstagramUrl>https?:\/\/(www.)?instagram.com\/p\/[^\/]+\/?)", RegexOptions.IgnoreCase | RegexOptions.Compiled);
37+
private readonly IHttpClientFactory _ClientFactory;
38+
39+
public ImageDescriptorCommand(IConfiguration config, IHttpClientFactory clientFactory) : this(config["FritzBot:VisionApiBaseUrl"], config["FritzBot:VisionApiKey"])
40+
{
41+
_ClientFactory = clientFactory;
42+
}
3943

40-
public ImageDescriptorCommand(string azureUrl, string azureKey)
41-
{
42-
_AzureUrl = azureUrl;
43-
_AzureApiKey = azureKey;
44-
}
44+
public ImageDescriptorCommand(string azureUrl, string azureKey)
45+
{
46+
_AzureUrl = azureUrl;
47+
_AzureApiKey = azureKey;
48+
}
4549

46-
public bool CanExecute(string userName, string fullCommandText)
47-
{
50+
public bool CanExecute(string userName, string fullCommandText)
51+
{
4852

49-
// Match the regular expression pattern against a text string.
50-
var imageCheck = _UrlCheck.Match(fullCommandText);
51-
if (imageCheck.Captures.Count == 0)
52-
return false;
53-
this.ImageUrl = imageCheck.Captures[0].Value;
53+
// TODO: Check the cooldown on the image descriptor
5454

55-
return (!ImageUrl.Contains('#') && imageCheck.Captures.Count > 0) && ValidImageType(ImageUrl).GetAwaiter().GetResult();
55+
// Match the regular expression pattern against a text string.
56+
var imageCheck = _UrlCheck.Match(fullCommandText);
57+
var instagramCheck = _InstagramCheck.Match(fullCommandText);
58+
if (imageCheck.Captures.Count == 0 && !instagramCheck.Success)
59+
return false;
5660

57-
async Task<bool> ValidImageType(string url) {
61+
if (imageCheck.Captures.Count != 0) this.ImageUrl = imageCheck.Captures[0].Value;
62+
if (instagramCheck.Captures.Count != 0)
63+
{
64+
this.Provider = ImageProviders.Instagram;
65+
this.ImageUrl = HandleInstagram(instagramCheck).GetAwaiter().GetResult();
66+
return !string.IsNullOrEmpty(this.ImageUrl);
67+
}
5868

59-
HttpResponseMessage response;
69+
return (!ImageUrl.Contains('#') && imageCheck.Captures.Count > 0) && ValidImageType(ImageUrl).GetAwaiter().GetResult();
6070

61-
using (var client = _ClientFactory.CreateClient("ImageDescriptor"))
71+
async Task<bool> ValidImageType(string url)
6272
{
63-
try
73+
74+
HttpResponseMessage response;
75+
76+
using (var client = _ClientFactory.CreateClient("ImageDescriptor"))
6477
{
65-
var request = new HttpRequestMessage
78+
try
6679
{
67-
Method = HttpMethod.Head,
68-
RequestUri = new Uri(url)
69-
};
70-
response = await client.SendAsync(request, cancellationToken: CancellationToken.None);
71-
response.EnsureSuccessStatusCode();
72-
} catch
73-
{
74-
return false;
75-
}
80+
var request = new HttpRequestMessage
81+
{
82+
Method = HttpMethod.Head,
83+
RequestUri = new Uri(url)
84+
};
85+
response = await client.SendAsync(request, cancellationToken: CancellationToken.None);
86+
response.EnsureSuccessStatusCode();
87+
}
88+
catch
89+
{
90+
return false;
91+
}
92+
93+
return (response.Content.Headers.ContentType.MediaType.ToLowerInvariant().StartsWith("image/"));
7694

77-
return (response.Content.Headers.ContentType.MediaType.ToLowerInvariant().StartsWith("image/"));
95+
}
7896

7997
}
8098

8199
}
82100

83-
}
84101

85-
/// param name="fullCommandText" (this is the URL of the image we already found)
86-
public async Task Execute(IChatService chatService, string userName, string fullCommandText)
87-
{
102+
/// param name="fullCommandText" (this is the URL of the image we already found)
103+
public async Task Execute(IChatService chatService, string userName, string fullCommandText)
104+
{
105+
106+
// Cheer 100 themichaeljolley 01/3/19
107+
// Cheer 300 electrichavoc 01/3/19
108+
// Cheer 300 devlead 01/3/19
109+
// Cheer 100 brandonsatrom 01/3/19
110+
// Cheer 642 cpayette 01/3/19
111+
// Cheer 500 robertables 01/3/19
112+
// Cheer 100 johanb 01/3/19
113+
// Cheer 1000 bobtabor 01/3/19
114+
115+
var result = string.Empty;
116+
117+
// TODO: Pull from ASP.NET Core Dependency Injection
118+
using (var client = _ClientFactory.CreateClient("ImageDescriptor"))
119+
{
120+
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _AzureApiKey);
88121

89-
// Cheer 100 themichaeljolley 01/3/19
90-
// Cheer 300 electrichavoc 01/3/19
91-
// Cheer 300 devlead 01/3/19
92-
// Cheer 100 brandonsatrom 01/3/19
93-
// Cheer 642 cpayette 01/3/19
94-
// Cheer 500 robertables 01/3/19
95-
// Cheer 100 johanb 01/3/19
96-
// Cheer 1000 bobtabor 01/3/19
122+
var requestParameters = "visualFeatures=Categories,Description,Color,Adult&language=en";
123+
var uri = _AzureUrl + "?" + requestParameters;
97124

98-
var result = string.Empty;
125+
var body = JsonConvert.SerializeObject(new { url = ImageUrl });
126+
var content = new StringContent(body, Encoding.UTF8, "application/json");
99127

100-
// TODO: Pull from ASP.NET Core Dependency Injection
101-
using (var client = _ClientFactory.CreateClient("ImageDescriptor"))
102-
{
103-
client.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _AzureApiKey);
128+
var apiResponse = await client.PostAsync(uri, content);
104129

105-
var requestParameters = "visualFeatures=Categories,Description,Color,Adult&language=en";
106-
var uri = _AzureUrl + "?" + requestParameters;
130+
try
131+
{
132+
apiResponse.EnsureSuccessStatusCode();
133+
}
134+
catch (Exception)
135+
{
136+
await chatService.SendMessageAsync($"Unable to inspect the image from {userName}");
137+
return;
138+
}
139+
result = await apiResponse.Content.ReadAsStringAsync();
140+
apiResponse.Dispose();
141+
}
107142

108-
var body = JsonConvert.SerializeObject(new { url = ImageUrl });
109-
var content = new StringContent(body, Encoding.UTF8, "application/json");
143+
var visionDescription = JsonConvert.DeserializeObject<VisionDescription>(result);
110144

111-
var apiResponse = await client.PostAsync(uri, content);
145+
if (visionDescription.adult.isAdultContent && visionDescription.adult.adultScore > 0.85F)
146+
{
147+
await chatService.SendMessageAsync($"Hey {userName} - we don't like adult content here!");
148+
// TODO: Timeout / Ban user
149+
return;
150+
}
112151

113-
try
152+
if (visionDescription.adult.isRacyContent)
114153
{
115-
apiResponse.EnsureSuccessStatusCode();
154+
await chatService.SendMessageAsync($"Hey {userName} - that's too racy ({visionDescription.adult.racyScore,0:P2}) for our chat room!");
155+
// TODO: Timeout user
156+
return;
116157
}
117-
catch (Exception)
158+
159+
if (visionDescription.description.captions.Length == 0 && visionDescription.categories.Length > 0)
118160
{
119-
await chatService.SendMessageAsync($"Unable to inspect the image from {userName}");
161+
await chatService.SendMessageAsync($"No caption for the image submitted by {userName}, but it is: '{string.Join(',', visionDescription.categories.Select(c => c.name))}'");
120162
return;
121163
}
122-
result = await apiResponse.Content.ReadAsStringAsync();
123-
apiResponse.Dispose();
124-
}
125164

126-
var visionDescription = JsonConvert.DeserializeObject<VisionDescription>(result);
165+
var description = string.Empty;
166+
if (Provider == ImageProviders.Instagram)
167+
{
168+
description = $"{userName} Instagram({_InstagramInfo.owner}) ({visionDescription.description.captions[0].confidence,0:P2}): {visionDescription.description.captions[0].text}";
169+
} else
170+
{
171+
description = $"{userName} Photo ({visionDescription.description.captions[0].confidence,0:P2}): {visionDescription.description.captions[0].text}";
172+
}
173+
174+
await chatService.SendMessageAsync(description);
175+
176+
}
177+
178+
179+
private async Task<string> HandleInstagram(Match instagramCheck)
180+
{
181+
182+
// Cheer 200 phrakberg 03/3/19
183+
184+
var url = instagramCheck.Groups["InstagramUrl"].Value + "?__a=1";
185+
var imageUrl = string.Empty;
186+
using (var client = _ClientFactory.CreateClient("ImageDescriptor"))
187+
{
127188

128-
if (visionDescription.adult.isAdultContent && visionDescription.adult.adultScore > 0.85F)
129-
{
130-
await chatService.SendMessageAsync($"Hey {userName} - we don't like adult content here!");
131-
// TODO: Timeout / Ban user
132-
return;
133-
}
189+
var json = await client.GetStringAsync(url);
190+
var theResponse = JObject.Parse(json);
134191

135-
if (visionDescription.adult.isRacyContent)
136-
{
137-
await chatService.SendMessageAsync($"Hey {userName} - that's too racy ({visionDescription.adult.racyScore,0:P2}) for our chat room!");
138-
// TODO: Timeout user
139-
return;
140-
}
192+
imageUrl = theResponse["graphql"]["shortcode_media"]["display_url"].Value<string>();
193+
_InstagramInfo = (theResponse["graphql"]["shortcode_media"]["owner"]["full_name"].Value<string>(),
194+
"");
141195

142-
if (visionDescription.description.captions.Length == 0 && visionDescription.categories.Length > 0)
143-
{
144-
await chatService.SendMessageAsync($"No caption for the image submitted by {userName}, but it is: '{string.Join(',', visionDescription.categories.Select(c => c.name))}'");
145-
return;
146-
}
196+
}
147197

148-
var description = $"{userName} Photo ({visionDescription.description.captions[0].confidence,0:P2}): {visionDescription.description.captions[0].text}";
198+
return imageUrl;
149199

150-
await chatService.SendMessageAsync(description);
200+
}
151201

152202
}
153-
}
203+
204+
public enum ImageProviders
205+
{
206+
None = 0,
207+
Instagram
208+
}
154209
}

0 commit comments

Comments
 (0)