次の方法で共有


例: Python を使用してカスタム スキルを作成する (アーカイブ済み)

この例はアーカイブされ、サポート対象外です。 Python と Visual Studio Code を使用して Web API カスタム スキルを作成する方法について説明しました。 この例では、カスタム スキル インターフェイスを実装する Azure 関数 を使用しました。

前提条件

Azure Function の作成

この例では、Azure 関数を使用して、Web API をホストするという概念を示していますが、その他の方法も可能です。 コグニティブ スキルのインターフェイス要件を満たしていれば、どのような方法を使用してもかまいません。 ただし、Azure Functions を使用すると、カスタム スキルを簡単に作成できます。

関数のプロジェクトを作成する

Visual Studio Code の Azure Functions プロジェクト テンプレートでは、Azure の関数アプリに発行できるローカル プロジェクトを作成します。 関数アプリを使用すると、リソースを管理、デプロイ、および共有するための論理ユニットとして関数をグループ化できます。

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、Azure Functions: Create new project... を検索して選択します。
  2. プロジェクト ワークスペースのディレクトリの場所を選択し、 [選択] をクリックします。 既に別のワークスペースの一部になっているプロジェクト フォルダーは使用しないでください。
  3. 関数アプリ プロジェクトの言語を選択します。 このチュートリアルでは、[Python] を選択します。
  4. Python のバージョンを選びます (Azure Functions では、バージョン 3.7.5 がサポートされています)。
  5. プロジェクトの最初の関数のテンプレートを選択します。 [HTTP トリガー] を選択して、HTTP によってトリガーされる関数を新しい関数アプリに作成します。
  6. 関数名を指定します。 このケースでは、「Concatenator」を使用しましょう。
  7. 認証レベルとして [関数] を選択します。 関数の HTTP エンドポイントを呼び出すには関数アクセス キーを使用します。
  8. プロジェクトを開く方法を指定します。 この手順では、[ワークスペースに追加] を選択して、現在のワークスペースに関数アプリを作成します。

Visual Studio Code によって、新しいワークスペースに関数アプリ プロジェクトが作成されます。 このプロジェクトには、host.json ファイルと local.settings.json 構成ファイルと、言語固有のプロジェクト ファイルが含まれています。

新しい HTTP によってトリガーされる関数は、関数アプリ プロジェクトの Concatenator フォルダーにも作成されます。 その中には、次の内容の "__init__.py" というファイルがあります。

import logging

import azure.functions as func


def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    name = req.params.get('name')
    if not name:
        try:
            req_body = req.get_json()
        except ValueError:
            pass
        else:
            name = req_body.get('name')

    if name:
        return func.HttpResponse(f"Hello {name}!")
    else:
        return func.HttpResponse(
             "Please pass a name on the query string or in the request body",
             status_code=400
        )

次に、カスタム スキル インターフェイスに従って、そのコードを変更してみましょう。 既定のコードを次の内容に置き換えます。

import logging
import azure.functions as func
import json

def main(req: func.HttpRequest) -> func.HttpResponse:
    logging.info('Python HTTP trigger function processed a request.')

    try:
        body = json.dumps(req.get_json())
    except ValueError:
        return func.HttpResponse(
             "Invalid body",
             status_code=400
        )
    
    if body:
        result = compose_response(body)
        return func.HttpResponse(result, mimetype="application/json")
    else:
        return func.HttpResponse(
             "Invalid body",
             status_code=400
        )


def compose_response(json_data):
    values = json.loads(json_data)['values']
    
    # Prepare the Output before the loop
    results = {}
    results["values"] = []
    
    for value in values:
        output_record = transform_value(value)
        if output_record != None:
            results["values"].append(output_record)
    return json.dumps(results, ensure_ascii=False)

## Perform an operation on a record
def transform_value(value):
    try:
        recordId = value['recordId']
    except AssertionError  as error:
        return None

    # Validate the inputs
    try:         
        assert ('data' in value), "'data' field is required."
        data = value['data']        
        assert ('text1' in data), "'text1' field is required in 'data' object."
        assert ('text2' in data), "'text2' field is required in 'data' object."
    except AssertionError  as error:
        return (
            {
            "recordId": recordId,
            "errors": [ { "message": "Error:" + error.args[0] }   ]       
            })

    try:                
        concatenated_string = value['data']['text1'] + " " + value['data']['text2']  
        # Here you could do something more interesting with the inputs

    except:
        return (
            {
            "recordId": recordId,
            "errors": [ { "message": "Could not complete operation for record." }   ]       
            })

    return ({
            "recordId": recordId,
            "data": {
                "text": concatenated_string
                    }
            })

transform_value メソッドは、1 つのレコードに対して操作を実行します。 このメソッドは、特定のニーズに合うように変更できます。 必ず、必要な入力検証を行い、操作を完了できない場合はエラーと警告が返されるようにしてください。

コードをローカルでデバッグする

Visual Studio Code では、コードを簡単にデバッグすることができます。 F5 キーを押すか、[デバッグ] メニューにアクセスして、[デバッグの開始] を選択します。

目的の行で F9 キーを押すと、コードにブレークポイントを設定できます。

デバッグを開始すると、関数がローカルで実行されます。 Postman や Fiddler などのツールを使用して、localhost に要求を発行できます。 ターミナル ウィンドウでローカル エンドポイントの場所を確認します。

Azure で関数アプリを作成する

関数の動作に満足したら、発行できます。 ここまでは、ローカルで作業してきました。 このセクションでは、Azure で関数アプリを作成し、作成したアプリにローカル プロジェクトをデプロイします。

Visual Studio Code からアプリを作成する

  1. Visual Studio Code で、F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、[Azure で関数アプリを作成する] を検索して選びます。

  2. アクティブなサブスクリプションが複数ある場合は、このアプリのサブスクリプションを選びます。

  3. 関数アプリのグローバルに一意の名前を入力します。 URL に有効な名前を入力します。

  4. ランタイム スタックを選び、ローカルで実行している言語バージョンを選びます。

  5. アプリの場所を選択します。 可能であれば、検索サービスをホストしているのと同じリージョンを選びます。

アプリの作成には数分かかります。 準備ができたら、アクティブなサブスクリプションの [リソース][関数アプリ] の下に新しいアプリが表示されます。

Azure にデプロイ

  1. 引き続き Visual Studio Code で F1 キーを押してコマンド パレットを開きます。 コマンド パレットで、[Deploy to Function App...](関数アプリにデプロイする...) を検索して選択します。

  2. 作成した関数アプリを選びます。

  3. 続行することを確認し、[ デプロイ] を選びます。 デプロイの状態は、出力ウィンドウで監視できます。

  4. Azure portal に切り替え、[すべてのリソース] に移動します。 前の手順で指定したグローバルに一意の名前を使用して、デプロイした関数アプリを検索します。

    ヒント

    Visual Studio Code で関数アプリを右クリックし、[ポータルで開く] を選ぶこともできます。

  5. ポータルの左側にある [関数] を選び、作成した関数を選びます。

  6. 関数の概要ページの上部のコマンド バーで [関数の URL の取得] を選びます。 これにより、関数を呼び出す URL をコピーできます。

    Azure portal の [関数の URL の取得] コマンドのスクリーンショット。

Azure で関数をテストする

コピーした既定のホスト キーと URL を使用して、Azure portal 内から関数をテストします。

  1. 左側の [開発者] で、[コードとテスト] を選びます。

  2. コマンド バーで [テストと実行] を選びます。

  3. 入力には、既定のキーである Post を使用し、要求本文に貼り付けます。

    {
        "values": [
            {
                "recordId": "e1",
                "data":
                {
                    "text1":  "Hello",
                    "text2":  "World"
                }
            },
            {
                "recordId": "e2",
                "data": "This is an invalid input"
            }
        ]
    }
    
  4. [実行] を選択します。

    入力仕様のスクリーンショット。

この例では、以前にローカル環境で関数を実行したときと同じ結果が得られるはずです。

スキルセットへの追加

新しいカスタム スキルが作成できたので、スキルセットに追加できます。 次の例は、スキルを呼び出して、ドキュメントのタイトルと作成者を連結して、merged_title_author という 1 つのフィールドを作成する方法を示しています。

[your-function-url-here] は、新しい Azure 関数の URL に置き換えます。

{
    "skills": [
      "[... other existing skills in the skillset are here]",  
      {
        "@odata.type": "#Microsoft.Skills.Custom.WebApiSkill",
        "description": "Our new search custom skill",
        "uri": "https://[your-function-url-here]",        
          "context": "/document/merged_content/organizations/*",
          "inputs": [
            {
              "name": "text1",
              "source": "/document/metadata_title"
            },
            {
              "name": "text2",
              "source": "/document/metadata_author"
            },
          ],
          "outputs": [
            {
              "name": "text",
              "targetName": "merged_title_author"
            }
          ]
      }
  ]
}

インデクサー定義に "outputFieldMapping" を追加して、検索インデックスの "fullname" フィールドに "merged_title_author" を送信することを忘れないでください。

"outputFieldMappings": [
    {
        "sourceFieldName": "/document/content/merged_title_author",
        "targetFieldName": "fullname"
    }
]