Örnek: Bing Varlık Arama API'sini kullanarak özel beceri oluşturma

Bu örnekte web API'sine özel beceri oluşturmayı öğrenin. Bu beceri konumları, genel kişileri ve kuruluşları kabul eder ve bunlar için açıklama döndürür. Örnek, Bing Varlık Arama API'sini özel beceri arabirimini uygulayacak şekilde sarmalayan bir Azure İşlevi kullanır.

Önkoşullar

Azure İşlevi oluşturma

Bu örnekte web API'sini barındırmak için Azure İşlevi kullanılıyor olsa da gerekli değildir. Bilişsel beceri için arabirim gereksinimlerini karşıladığınız sürece, benimsediğiniz yaklaşım önemsizdir. Ancak Azure İşlevleri, özel beceri oluşturmayı kolaylaştırır.

Bir proje oluştur

  1. Visual Studio'da Dosya menüsünden Yeni>Proje'yi seçin.

  2. Şablon olarak Azure İşlevleri seçin ve İleri'yi seçin. Projeniz için bir ad yazın ve Oluştur'u seçin. İşlev uygulaması adı C# ad alanı olarak geçerli olmalıdır, bu nedenle alt çizgileri, kısa çizgileri veya alfasayısal olmayan diğer karakterleri kullanmayın.

  3. Uzun vadeli desteği olan bir çerçeve seçin.

  4. Projeye eklenecek işlev türü için HTTP Tetikleyicisi'ni seçin.

  5. Yetkilendirme düzeyi için İşlev'i seçin.

  6. İşlev projesini ve HTTP ile tetiklenen işlevi oluşturmak için Oluştur'u seçin.

Bing Varlık API'sini çağırmak için kod ekleme

Visual Studio, seçilen işlev türü için ortak kod içeren bir proje oluşturur. Metottaki FunctionName özniteliği işlevin adını ayarlar. HttpTrigger özniteliği, işlevin bir HTTP isteği tarafından tetiklenip tetiklenmediğini belirtir.

Function1.cs içeriğini aşağıdaki kodla değiştirin:

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
    }
}

Bing varlık arama API'sine key kaydolırken edindiğiniz anahtara göre sabite kendi anahtar değerinizi girdiğinizden emin olun.

Visual Studio'dan işlevi test edin

Programı çalıştırmak ve işlev davranışlarını test etmek için F5 tuşuna basın. Bu durumda, iki varlığı aramak için aşağıdaki işlevi kullanacağız. Aşağıda gösterilene benzer bir çağrı yapmak için REST istemcisini kullanın:

POST https://localhost:7071/api/EntitySearch

Request body

{
    "values": [
        {
            "recordId": "e1",
            "data":
            {
                "name":  "Pablo Picasso"
            }
        },
        {
            "recordId": "e2",
            "data":
            {
                "name":  "Microsoft"
            }
        }
    ]
}

Yanıtla

Aşağıdaki örneğe benzer bir yanıt görmeniz gerekir:

{
    "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
        },
        "..."
    ]
}

İşlevi Azure’a yayımlama

İşlev davranışından memnun olduğunuzda yayımlayabilirsiniz.

  1. Çözüm Gezgini'nde projeye sağ tıklayın ve Yayımla'yı seçin. Yeni Yayımla Oluştur'u> seçin.

  2. Henüz Visual Studio'yu Azure hesabınıza bağlamadıysanız Hesap ekle... öğesini seçin.

  3. Ekrandaki istemleri izleyin. Uygulama hizmetiniz, Azure aboneliğiniz, kaynak grubunuz, barındırma planınız ve kullanmak istediğiniz depolama hesabınız için benzersiz bir ad belirtmeniz istenir. Henüz bu kaynaklara sahip değilseniz yeni bir kaynak grubu, yeni bir barındırma planı ve depolama hesabı oluşturabilirsiniz. İşiniz bittiğinde Oluştur'u seçin

  4. Dağıtım tamamlandıktan sonra Site URL'sine dikkat edin. Bu, Azure'daki işlev uygulamanızın adresidir.

  5. Azure portalında Kaynak Grubu'na gidin ve yayımladığınız İşlevi EntitySearch arayın. Yönet bölümünde Konak Anahtarları'nı görmeniz gerekir. Varsayılan konak anahtarı için Kopyala simgesini seçin.

İşlevi Azure'da test edin

Artık varsayılan ana bilgisayar anahtarına sahip olduğunuz için işlevinizi aşağıdaki gibi test edin:

POST https://[your-entity-search-app-name].azurewebsites.net/api/EntitySearch?code=[enter default host key here]

İstek Gövdesi

{
    "values": [
        {
            "recordId": "e1",
            "data":
            {
                "name":  "Pablo Picasso"
            }
        },
        {
            "recordId": "e2",
            "data":
            {
                "name":  "Microsoft"
            }
        }
    ]
}

Bu örnek, işlevi yerel ortamda çalıştırırken daha önce gördüğünüz sonucun aynısını üretmelidir.

İşlem hattınıza bağlanma

Artık yeni bir özel beceriniz olduğuna göre, beceri kümesine ekleyebilirsiniz. Aşağıdaki örnekte, belgedeki kuruluşlara açıklama ekleme becerisini nasıl çağırabileceğiniz gösterilmektedir (bu, konumlar ve kişiler üzerinde de çalışacak şekilde genişletilebilir). değerini uygulamanızın adıyla değiştirin [your-entity-search-app-name] .

{
    "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"
            }
          ]
      }
  ]
}

Burada, beceri kümesinde mevcut olacak ve belgeyi kuruluş listesiyle zenginleştirmiş olacak yerleşik varlık tanıma becerisine güveniyoruz. Başvuru için, ihtiyacımız olan verileri oluşturmak için yeterli olabilecek bir varlık ayıklama beceri yapılandırması aşağıdadır:

{
    "@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"
        }
    ]
},

Sonraki adımlar

Tebrikler! İlk özel becerinizi oluşturdunuz. Artık kendi özel işlevselliğinizi eklemek için aynı deseni izleyebilirsiniz. Daha fazla bilgi edinmek için aşağıdaki bağlantılara tıklayın.