-
Notifications
You must be signed in to change notification settings - Fork 2
/
PluginEndpoint.cs
126 lines (103 loc) · 5.33 KB
/
PluginEndpoint.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using System.Diagnostics.CodeAnalysis;
using System.Net;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.OpenApi.Extensions;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.WebJobs.Extensions.OpenApi.Core.Attributes;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
public class PluginEndpoint
{
private readonly ILogger _logger;
private readonly AppConfig _appConfig;
public PluginEndpoint(AppConfig appConfig, ILoggerFactory loggerFactory)
{
_appConfig = appConfig;
_logger = loggerFactory.CreateLogger<PluginEndpoint>();
}
[Function("WellKnownAIPlugin")]
public async Task<HttpResponseData> WellKnownAIPlugin(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", Route=".well-known/ai-plugin.json")] HttpRequestData req)
{
var toReturn = new AIPlugin();
toReturn.Api.Url = $"{req.Url.Scheme}://{req.Url.Host}:{req.Url.Port}/swagger.json";
var r = req.CreateResponse(HttpStatusCode.OK);
await r.WriteAsJsonAsync(toReturn);
return r;
}
[OpenApiOperation(operationId: "Search", tags: new[] { "WebSearchFunction" }, Description = "Searches the web for the given query.")]
[OpenApiParameter(name: "Query", Description = "The query", Required = true, In = ParameterLocation.Query)]
[OpenApiParameter(name: "NumResults", Description = "The maximum number of results to return", Required = true, In = ParameterLocation.Query)]
[OpenApiParameter(name: "Offset", Description = "The number of results to skip", Required = false, In = ParameterLocation.Query)]
[OpenApiParameter(name: "Site", Description = "The specific site to search within.", Required = false, In = ParameterLocation.Query)]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.OK, contentType: "text/plain", bodyType: typeof(string), Description = "Returns a collection of search results with the name, URL and snippet for each.")]
[OpenApiResponseWithBody(statusCode: HttpStatusCode.BadRequest, contentType: "application/json", bodyType: typeof(string), Description = "Returns the error of the input.")]
[Function("WebSearch")]
public async Task<HttpResponseData> WebSearch([HttpTrigger(AuthorizationLevel.Anonymous, "get", Route="search")] HttpRequestData req)
{
var query = req.Query("Query").FirstOrDefault();
if (query == null)
{
return req.CreateResponse(HttpStatusCode.BadRequest);
}
var numResults = req.Query("NumResults").FirstOrDefault();
if (numResults == null)
{
return req.CreateResponse(HttpStatusCode.BadRequest);
}
var offset = req.Query("Offset").FirstOrDefault();
var offsetInt = offset == null ? 0 : int.Parse(offset);
var site = req.Query("Site").FirstOrDefault(string.Empty);
if (string.IsNullOrWhiteSpace(site))
{
_logger.LogInformation($"Starting search for: {query}");
}
else
{
_logger.LogInformation($"Starting search within {site} for: {query}");
}
using (var httpClient = new HttpClient())
{
var siteQueryString = string.IsNullOrWhiteSpace(site) ? string.Empty : $"+site:{site}";
var uri = new Uri($"https://api.bing.microsoft.com/v7.0/search?q={Uri.EscapeDataString(query)}{siteQueryString}&count={numResults}&offset={offsetInt}");
httpClient.DefaultRequestHeaders.Add("Ocp-Apim-Subscription-Key", _appConfig.BingApiKey);
var json = await httpClient.GetStringAsync(uri);
_logger.LogInformation($"Search completed for: {query}");
BingSearchResponse? data = JsonSerializer.Deserialize<BingSearchResponse>(json);
WebPage[]? results = data?.WebPages?.Value;
var r = req.CreateResponse(HttpStatusCode.OK);
r.Headers.Add("Content-Type", "text/plain");
await r.WriteStringAsync(results == null ?
"No results found" :
string.Join(",", results.Select(x => $"[NAME]{x.Name}[END NAME] [URL]{x.Url}[END URL] [SNIPPET]{x.Snippet}[END SNIPPET]")));
return r;
}
}
[SuppressMessage("Performance", "CA1812:Internal class that is apparently never instantiated",
Justification = "Class is instantiated through deserialization.")]
private sealed class BingSearchResponse
{
[JsonPropertyName("webPages")]
public WebPages? WebPages { get; set; }
}
[SuppressMessage("Performance", "CA1812:Internal class that is apparently never instantiated",
Justification = "Class is instantiated through deserialization.")]
private sealed class WebPages
{
[JsonPropertyName("value")]
public WebPage[]? Value { get; set; }
}
[SuppressMessage("Performance", "CA1812:Internal class that is apparently never instantiated",
Justification = "Class is instantiated through deserialization.")]
private sealed class WebPage
{
[JsonPropertyName("name")]
public string Name { get; set; } = string.Empty;
[JsonPropertyName("url")]
public string Url { get; set; } = string.Empty;
[JsonPropertyName("snippet")]
public string Snippet { get; set; } = string.Empty;
}
}