watsonx.aiの基盤モデルをWatson Discoveryのエンティティ抽出で利用する

# はじめに
Watson Discovery には文書から意味を抽出してタグ付けをする機能が豊富にあります。最近ではwebhookを利用して文書にアノテーションを付けるための外部エンリッチ機能が提供されています。
これにより、watsonx.ai などの基盤モデルを利用して、文書にタグ付けができるようになります。付与されたタグは文書検索の絞り込みや分析条件に利用できます。
ここでは、watsonx.aiの基盤モデルを利用して、Eメールからエンティティ（人名,会社名,場所など）を抽出する手順を紹介します。
基盤モデルとしては、IBMのGraniteを利用しています。

# 準備
### 実行環境
IBM Cloud で提供している以下のサービスを利用します。これらのサービスをIBM Cloudで利用できるように作成します。
* [**Watson Discovery**](https://www.ibm.com/jp-ja/products/watson-discovery)
* [**watsonx.ai**](https://www.ibm.com/jp-ja/products/watsonx-ai) 
* [**Code Engine**](https://www.ibm.com/jp-ja/products/code-engine)

:::note info
Discoveryは30日間の無料トライアル、watsonx.aiとCodeEngineは無料枠で試すことができます。
:::

## エンリッチアプリケーションを Code Engineにデプロイ
今回のサンプルは、Webhook エンリッチを適用するための環境として IBM Cloud Code Engine を使用しています。 他の環境にアプリケーションをデプロイすることもできます。

### IBM Cloud Code Engine でプロジェクトを作成
[Code Engine コンソールの「プロジェクト」ページ](https://cloud.ibm.com/codeengine/projects) から、 作成をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/0d0a42fd-2437-bdb7-78e7-3831bd2cedd7.png)
- 情報を入力
**ロケーション** を選択
作成するプロジェクトの **名前** を入力
**リソースグループ**　を選択
- 「作成」をクリック

### プロジェクト内にシークレットを作成します
作成したプロジェクトで「シークレット及び configmap」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/695415b8-8752-a0fb-ee16-5a5255f65738.png)
「作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/93bbd57e-b5fd-92e7-1012-83a90946786c.png)
- オプションの選択で **「シークレット」** を選択
- 名前：*「任意の名前」*　 （後で利用します）
- 「キーと値のペアを追加」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/01390202-0111-8b16-44c7-4895ee870b90.png)
_WD_API_URL:_ **Discoveryインスタンスの資格情報にある URL**
_WD_API_KEY:_ **Discoveryインスタンスの資格情報にある API鍵**
_WEBHOOK_SECRET:_ **アプリケーションの認証に使用する任意の文字列** （DiscoveryのWebhook登録時に使用）
_IBM_CLOUD_API_KEY:_ **IBM Cloudの API キー**
_WML_ENDPOINT_URL:_ **Watson Machine Learningの API エンドポイントURL**。watsonx.aiがダラスの場合は **https://us-south.ml.cloud.ibm.com** です。詳細は[マニュアル](https://cloud.ibm.com/apidocs/machine-learning)を参照
_WML_INSTANCE_CRN:_ **Watson Machine Learning のインスタンスの ID**。 IBM Cloudのリソースリストから確認できます。（crn:で始まる文字列）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/fb002e38-860a-ee6a-700e-fc99bed382e3.png)



### サンプルリポジトリーのソースコードからアプリケーションをデプロイ
プロジェクトで「概要」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/bcba5922-af21-54c8-6cc8-49402dbf7fd2.png)
- 「アプリケーション作成」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/a81d5171-d4e0-620d-859f-4bbb4925c8f5.png)
*名前：* [**任意の名前**]
*実行するコードの選択：* **ソース・コード**
*ソース・コード URL：* **https://github.com/watson-developer-cloud/doc-tutorial-downloads**

- 「ビルド詳細の指定」をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/685a4a46-efb6-9782-73e9-a6b9449a80d6.png)
*コード・リポジトリURL：* **https://github.com/watson-developer-cloud/doc-tutorial-downloads**
*コード・リポジトリー・アクセス：* **なし**
*ブランチ名：* **master**
*コンテキスト・ディレクトリー：* **discovery-data/webhook-enrichment-sample/granite**
*戦略：* **「Dockerfile」**　を選択

下にスクロールして、「環境変数（オプション）」を選択
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/4f9422c1-9444-9cfd-3884-ddf265b69c97.png)
「追加」をクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/f9e7219f-cf4d-d337-2043-2caaac1af560.png)
*定義タイプ：*　「**シークレット全体の参照**」を選択
*シークレット：* [[前のステップでプロジェクトに作成したシークレットの名前]](https://qiita.com/Jungobu/private/558d6b3074879f1d8bfe#%E3%83%97%E3%83%AD%E3%82%B8%E3%82%A7%E3%82%AF%E3%83%88%E5%86%85%E3%81%AB%E3%82%B7%E3%83%BC%E3%82%AF%E3%83%AC%E3%83%83%E3%83%88%E3%82%92%E4%BD%9C%E6%88%90%E3%81%97%E3%81%BE%E3%81%99)を入力

アプリケーションの作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/68b7f2ed-8cf1-7625-dcbd-d33472780948.png)
「作成」をクリックしてアプリケーションを作成します

## Watson DiscovryでWebhook エンリッチメントの構成

### Webhook エンリッチメントの登録
Discovery API を使用して Webhook エンリッチを作成します。

Webhookエンリッチメントの登録は、以下のフォーマットです
```sh
curl -X POST {auth} \
--header 'Content-Type: multipart/form-data' \
--form 'enrichment={"name":"my-first-webhook-enrichment", \
"type":"webhook", \
"options":{"url":"{your_code_engine_app_domain}/webhook", \
    "secret":"{your_webhook_secret}", \
    "location_encoding":"utf-32"}}' \
'{url}/v2/projects/{project_id}/enrichments?version=2023-03-31'
```
_{auth}:_ **apikey:[IBM Cloudの APIキー**]
_{your_code_engine_app_domain}：_**Code Engine の アプリケーション > ドメイン・マッピングで確認**
_{your_webhook_secret}：_　前のステップで登録した **WEBHOOK_SECRET** の値
_{url}：_　**Discoveryインスタンスの資格情報にある URL**
_{project_id}：_ Discoveryの「Integrate and deploy」>「API Information」タブの **Project ID**

実際に登録した時のコマンドはこのようなイメージです
```sh
curl -X POST -u "apikey:abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqr" \
--header 'Content-Type: multipart/form-data' \
--form 'enrichment={"name":"watsonx", \
"type":"webhook", \
"options":{"url":"https://watsonx-entity.1abc2defg3h4.us-south.codeengine.appdomain.cloud/webhook",\
    "secret":"hooksecret", \
    "location_encoding":"utf-32"}}' \
'https://api.us-south.discovery.watson.cloud.ibm.com/instances/1234567c-d123-456d-bad7-5e50d920cc5e/v2/projects/d12345fa-ef67-8cbd-ace9-0a6e123a45c6/enrichments?version=2023-03-31'
```
## Discoveryでエンリッチメントの構成
### コレクションにサンプルファイルの登録
[Discovery doc-tutorial-downloads](https://github.com/watson-developer-cloud/doc-tutorial-downloads/tree/master/discovery-data/webhook-enrichment-sample/granite/data) から email.txt ダウンロードして、Discoveryのコレクションに登録（アップロード）します。

### コレクションにエンリッチメントの指定
Discoveryの管理ツールで、Webhookで登録したエンリッチメントを指定します
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/598ba032-4300-a3ae-26ed-689bc282deaa.png)

### 文書に付与されたエンリッチメントの確認
Discoveryで文書のメタ情報を見ると、webhookエンリッチメントで情報が抽出されているのを確認できます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1322004/1e242936-cbc7-ad4b-81c9-140bcf8a11ac.png)


## 終わりに
Watson Discoveryの特徴的な機能であるエンリッチメントで、汎用的なwebhookが利用できるようになりました。
今回は watsonx.ai の Griniteモデル を利用してエンティティ抽出を行いました。
サンプルテンプレートは granite-13b-instruct-v1 モデルで英語のプロンプトを使用していますが、以下の **model_id** や **Input** のプロンプトを変更して、別の結果を試すことができます。


https://github.com/watson-developer-cloud/doc-tutorial-downloads/blob/master/discovery-data/webhook-enrichment-sample/granite/main.py


```py:main.py
def extract_entities(text):
    global IAM_TOKEN
    if IAM_TOKEN is None:
        IAM_TOKEN = get_iam_token()
    # Prompt
    payload = {
        'model_id': 'ibm/granite-13b-instruct-v1',
        'input': f'''Act as a webmaster who must extract structured information from emails. Read the below email and extract and categorize each entity. If no entity is found, output "None".

Input:
"Golden Bank is a competitor of Silver Bank in the US" said John Doe.

Named Entities:
Golden Bank: company, Silver Bank: company, US: country, John Doe: person

Input:
{text}
```
---
# 参考情報
**Watson Discovery 製品マニュアル：Discoveryで外部Webhookエンリッチを作成**
https://cloud.ibm.com/docs/discovery-data?topic=discovery-data-tutorial-external-enrichment#configure-webhook-enrichment

**Watson Discovdery 外部エンリッチ API**
https://cloud.ibm.com/docs/discovery-data?topic=discovery-data-external-enrichment