Példa: Egyéni képesség létrehozása a Bing Entity Search API használatával
Ebben a példában megtudhatja, hogyan hozhat létre egyéni webes API-képességet. Ez a képesség helyeket, közszereplőket és szervezeteket fogad el, és leírásokat ad vissza hozzájuk. A példa egy Azure-függvény használatával burkolja be a Bing Entity Search API-t, hogy megvalósítsa az egyéni készségfelületet.
Előfeltételek
Ha nem ismeri az egyéni képesség által implementálandó bemeneti/kimeneti felületet, olvassa el az egyéni készség felületéről szóló cikket.
Bing Search-erőforrás létrehozása az Azure Portalon. Ehhez a példához ingyenes szint érhető el és elegendő.
Telepítse a Visual Studiót vagy újabb verziót.
Azure-függvény létrehozása
Bár ez a példa egy Azure-függvényt használ egy webes API üzemeltetéséhez, nem szükséges. Mindaddig, amíg megfelel a kognitív képességek felületi követelményeinek, az ön által használt megközelítés nem lényegtelen. Az Azure Functions azonban megkönnyíti az egyéni képességek létrehozását.
Projekt létrehozása
A Visual Studióban válassza az Új>projekt lehetőséget a Fájl menüből.
Válassza az Azure Functionst sablonként, és válassza a Tovább gombot. Írja be a projekt nevét, és válassza a Létrehozás lehetőséget. A függvényalkalmazás nevének C#-névtérként kell érvényesnek lennie, ezért ne használjon aláhúzásjeleket, kötőjeleket vagy más nem alfanumerikus karaktereket.
Válasszon ki egy hosszú távú támogatást igénylő keretrendszert.
Válassza a HTTP-eseményindítót a projekthez hozzáadni kívánt függvény típusához.
Válassza a függvényt az engedélyezési szinthez.
Válassza a Létrehozás lehetőséget a függvényprojekt és a HTTP által aktivált függvény létrehozásához.
Kód hozzáadása a Bing Entity API meghívásához
A Visual Studio létrehoz egy projektet a kiválasztott függvénytípushoz tartozó sablonkóddal. A metódus FunctionName attribútuma adja meg a függvény nevét. A HttpTrigger attribútum adja meg, hogy a függvényt egy HTTP-kérelem aktiválja.
Cserélje le a Function1.cs tartalmát a következő kódra:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace SampleSkills
{
/// <summary>
/// Sample custom skill that wraps the Bing entity search API to connect it with a
/// AI enrichment pipeline.
/// </summary>
public static class BingEntitySearch
{
#region Credentials
// IMPORTANT: Make sure to enter your credential and to verify the API endpoint matches yours.
static readonly string bingApiEndpoint = "https://api.bing.microsoft.com/v7.0/entities";
static readonly string key = "<enter your api key here>";
#endregion
#region Class used to deserialize the request
private class InputRecord
{
public class InputRecordData
{
public string Name { get; set; }
}
public string RecordId { get; set; }
public InputRecordData Data { get; set; }
}
private class WebApiRequest
{
public List<InputRecord> Values { get; set; }
}
#endregion
#region Classes used to serialize the response
private class OutputRecord
{
public class OutputRecordData
{
public string Name { get; set; } = "";
public string Description { get; set; } = "";
public string Source { get; set; } = "";
public string SourceUrl { get; set; } = "";
public string LicenseAttribution { get; set; } = "";
public string LicenseUrl { get; set; } = "";
}
public class OutputRecordMessage
{
public string Message { get; set; }
}
public string RecordId { get; set; }
public OutputRecordData Data { get; set; }
public List<OutputRecordMessage> Errors { get; set; }
public List<OutputRecordMessage> Warnings { get; set; }
}
private class WebApiResponse
{
public List<OutputRecord> Values { get; set; }
}
#endregion
#region Classes used to interact with the Bing API
private class BingResponse
{
public BingEntities Entities { get; set; }
}
private class BingEntities
{
public BingEntity[] Value { get; set; }
}
private class BingEntity
{
public class EntityPresentationinfo
{
public string[] EntityTypeHints { get; set; }
}
public class License
{
public string Url { get; set; }
}
public class ContractualRule
{
public string _type { get; set; }
public License License { get; set; }
public string LicenseNotice { get; set; }
public string Text { get; set; }
public string Url { get; set; }
}
public ContractualRule[] ContractualRules { get; set; }
public string Description { get; set; }
public string Name { get; set; }
public EntityPresentationinfo EntityPresentationInfo { get; set; }
}
#endregion
#region The Azure Function definition
[FunctionName("EntitySearch")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequest req,
ILogger log)
{
log.LogInformation("Entity Search function: C# HTTP trigger function processed a request.");
var response = new WebApiResponse
{
Values = new List<OutputRecord>()
};
string requestBody = new StreamReader(req.Body).ReadToEnd();
var data = JsonConvert.DeserializeObject<WebApiRequest>(requestBody);
// Do some schema validation
if (data == null)
{
return new BadRequestObjectResult("The request schema does not match expected schema.");
}
if (data.Values == null)
{
return new BadRequestObjectResult("The request schema does not match expected schema. Could not find values array.");
}
// Calculate the response for each value.
foreach (var record in data.Values)
{
if (record == null || record.RecordId == null) continue;
OutputRecord responseRecord = new OutputRecord
{
RecordId = record.RecordId
};
try
{
responseRecord.Data = GetEntityMetadata(record.Data.Name).Result;
}
catch (Exception e)
{
// Something bad happened, log the issue.
var error = new OutputRecord.OutputRecordMessage
{
Message = e.Message
};
responseRecord.Errors = new List<OutputRecord.OutputRecordMessage>
{
error
};
}
finally
{
response.Values.Add(responseRecord);
}
}
return (ActionResult)new OkObjectResult(response);
}
#endregion
#region Methods to call the Bing API
/// <summary>
/// Gets metadata for a particular entity based on its name using Bing Entity Search
/// </summary>
/// <param name="entityName">The name of the entity to extract data for.</param>
/// <returns>Asynchronous task that returns entity data. </returns>
private async static Task<OutputRecord.OutputRecordData> GetEntityMetadata(string entityName)
{
var uri = bingApiEndpoint + "?q=" + entityName + "&mkt=en-us&count=10&offset=0&safesearch=Moderate";
var result = new OutputRecord.OutputRecordData();
using (var client = new HttpClient())
using (var request = new HttpRequestMessage {
Method = HttpMethod.Get,
RequestUri = new Uri(uri)
})
{
request.Headers.Add("Ocp-Apim-Subscription-Key", key);
HttpResponseMessage response = await client.SendAsync(request);
string responseBody = await response?.Content?.ReadAsStringAsync();
BingResponse bingResult = JsonConvert.DeserializeObject<BingResponse>(responseBody);
if (bingResult != null)
{
// In addition to the list of entities that could match the name, for simplicity let's return information
// for the top match as additional metadata at the root object.
return AddTopEntityMetadata(bingResult.Entities?.Value);
}
}
return result;
}
private static OutputRecord.OutputRecordData AddTopEntityMetadata(BingEntity[] entities)
{
if (entities != null)
{
foreach (BingEntity entity in entities.Where(
entity => entity?.EntityPresentationInfo?.EntityTypeHints != null
&& (entity.EntityPresentationInfo.EntityTypeHints[0] == "Person"
|| entity.EntityPresentationInfo.EntityTypeHints[0] == "Organization"
|| entity.EntityPresentationInfo.EntityTypeHints[0] == "Location")
&& !String.IsNullOrEmpty(entity.Description)))
{
var rootObject = new OutputRecord.OutputRecordData
{
Description = entity.Description,
Name = entity.Name
};
if (entity.ContractualRules != null)
{
foreach (var rule in entity.ContractualRules)
{
switch (rule._type)
{
case "ContractualRules/LicenseAttribution":
rootObject.LicenseAttribution = rule.LicenseNotice;
rootObject.LicenseUrl = rule.License.Url;
break;
case "ContractualRules/LinkAttribution":
rootObject.Source = rule.Text;
rootObject.SourceUrl = rule.Url;
break;
}
}
}
return rootObject;
}
}
return new OutputRecord.OutputRecordData();
}
#endregion
}
}
A Bing entitáskeresési API-ra való regisztrációkor kapott kulcs alapján mindenképpen adja meg a saját kulcsértékét az állandóban key
.
A függvény tesztelése a Visual Studióból
Nyomja le az F5 billentyűt a program futtatásához és a függvény viselkedésének teszteléséhez. Ebben az esetben az alábbi függvény használatával keresünk két entitást. A REST-ügyfél használatával az alábbihoz hasonló hívást kezdeményezhet:
POST https://localhost:7071/api/EntitySearch
Kérés törzse
{
"values": [
{
"recordId": "e1",
"data":
{
"name": "Pablo Picasso"
}
},
{
"recordId": "e2",
"data":
{
"name": "Microsoft"
}
}
]
}
Válasz
A következő példához hasonló választ kell látnia:
{
"values": [
{
"recordId": "e1",
"data": {
"name": "Pablo Picasso",
"description": "Pablo Ruiz Picasso was a Spanish painter [...]",
"source": "Wikipedia",
"sourceUrl": "http://en.wikipedia.org/wiki/Pablo_Picasso",
"licenseAttribution": "Text under CC-BY-SA license",
"licenseUrl": "http://creativecommons.org/licenses/by-sa/3.0/"
},
"errors": null,
"warnings": null
},
"..."
]
}
A függvény közzététele az Azure-ban
Ha elégedett a függvény viselkedésével, közzéteheti.
A Megoldáskezelőben kattintson a jobb gombbal a projektre, és válassza a Publish (Közzététel) lehetőséget. Válassza az Új>közzététel létrehozása lehetőséget.
Ha még nem csatlakoztatta a Visual Studiót az Azure-fiókjához, válassza a Fiók hozzáadása... lehetőséget.
Kövesse a képernyőn megjelenő utasításokat. A rendszer arra kéri, hogy adjon meg egy egyedi nevet az app service-nek, az Azure-előfizetésnek, az erőforráscsoportnak, az üzemeltetési csomagnak és a használni kívánt tárfióknak. Ha még nem rendelkezik ezekkel, létrehozhat egy új erőforráscsoportot, egy új üzemeltetési tervet és egy tárfiókot. Ha végzett, válassza a Létrehozás lehetőséget
Az üzembe helyezés befejezése után figyelje meg a webhely URL-címét. Ez az Azure-beli függvényalkalmazás címe.
Az Azure Portalon keresse meg az erőforráscsoportot, és keresse meg a
EntitySearch
közzétett függvényt. A Kezelés szakaszban meg kell jelennie a gazdagépkulcsoknak. Válassza az alapértelmezett gazdagépkulcs Másolás ikonjának kiválasztását.
A függvény tesztelése az Azure-ban
Most, hogy már rendelkezik az alapértelmezett gazdagépkulcspel, tesztelje a függvényt az alábbiak szerint:
POST https://[your-entity-search-app-name].azurewebsites.net/api/EntitySearch?code=[enter default host key here]
Kérelem törzse
{
"values": [
{
"recordId": "e1",
"data":
{
"name": "Pablo Picasso"
}
},
{
"recordId": "e2",
"data":
{
"name": "Microsoft"
}
}
]
}
Ennek a példának ugyanazt az eredményt kell eredményeznie, amit korábban a függvény helyi környezetben való futtatásakor látott.
Csatlakozás a folyamathoz
Most, hogy új egyéni képességekkel rendelkezik, hozzáadhatja azt a készségkészlethez. Az alábbi példa bemutatja, hogyan hívhatja meg a készséget, hogy leírásokat adjon hozzá a dokumentumban található szervezetekhez (ez kiterjeszthető a helyeken és személyeken való munkavégzésre is). Cserélje le [your-entity-search-app-name]
az alkalmazás nevére.
{
"skills": [
"[... your existing skills remain here]",
{
"@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
"description": "Our new Bing entity search custom skill",
"uri": "https://[your-entity-search-app-name].azurewebsites.net/api/EntitySearch?code=[enter default host key here]",
"context": "/document/merged_content/organizations/*",
"inputs": [
{
"name": "name",
"source": "/document/merged_content/organizations/*"
}
],
"outputs": [
{
"name": "description",
"targetName": "description"
}
]
}
]
}
Itt arra számítunk, hogy a beépített entitásfelismerő képesség jelen lesz a képességkészletben, és a dokumentumot a szervezetek listájával bővítjük. Az alábbiakban egy entitás-kinyerési képesség konfigurációját tekintjük át, amely elegendő lenne a szükséges adatok létrehozásához:
{
"@odata.type": "#Microsoft.Skills.Text.V3.EntityRecognitionSkill",
"name": "#1",
"description": "Organization name extraction",
"context": "/document/merged_content",
"categories": [ "Organization" ],
"defaultLanguageCode": "en",
"inputs": [
{
"name": "text",
"source": "/document/merged_content"
},
{
"name": "languageCode",
"source": "/document/language"
}
],
"outputs": [
{
"name": "organizations",
"targetName": "organizations"
}
]
},
Következő lépések
Gratulálunk! Létrehozta az első egyéni készségét. Most már ugyanezt a mintát követve hozzáadhatja saját egyéni funkcióit. További információért kattintson az alábbi hivatkozásokra.