流行りのシスコ製品のAIアシスタントを日本語対応してみる

# :penguin: はじめに
この記事はシスコの同志による Advent Calendar の一部として投稿しています

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2021年版: https://qiita.com/advent-calendar/2021/cisco
2022年版: https://qiita.com/advent-calendar/2022/cisco
2023年版: https://qiita.com/advent-calendar/2023/cisco
2024年版: https://qiita.com/advent-calendar/2024/cisco

本記事は2024年版Advent Calendarの9日目の投稿になり、私自身としては5回目の投稿となります。今年は最近製品への実装が流行っているAIアシスタントの日本語対応に取り組んでみました。

# :penguin: 背景：
最近のシスコ製品にはAIアシスタントと言う機能が実装されており、生成AIを使って、ChatGPTのように問合せをすることで、GUIをクリックしていかなくても必要な情報を探し出してくれる機能があります。シスコのセキュリティ製品にも多く実装されつつあるのですが、残念ながら日本語サポートは少し先になるケースが多いので、当面は英語で問合せて、英語で回答を得ることになるます。今回はAPIを活用して、英語が苦手な自分用に、DeepL(無償版)と連携することでシスコセキュリティの1つであるSecurity Cloud Control(旧CDO： Cisco Defense Orchestrator)のAIアシスタントを日本語化対応してみました。

SCCのAIアシスタントユーザガイド
https://docs.defenseorchestrator.com/cdfmc/c_getting_started_with_ai_assistant_.html#!g_firewall-policy-assistant.html

シスコのAIアシスタントのポートフォリオが分かる資料(Ciscoアカウントが必要かも)
https://www.ciscolive.com/c/dam/r/ciscolive/apjc/docs/2024/pdf/BRKAPP-2546.pdf

# :penguin: 本来のAIアシスタントの利用画面イメージ
![SCC_Top01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/1918c3c4-a207-2eda-41e7-44bb602aac6f.png)

SCCにログインすると(Issuesがあるのは無視してください。)、右上に赤枠で括ったAIアシスタントを起動するボタンがあるのが分かります。そのボタンをクリックすることで添付のようなAIアシスタントが出て来てここから英語での問合せが可能になります。ただ、テストした時点(2024年11月上旬)では残念ながら日本語対応は正式には未リリースなのです。
![AI-Assist01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/368f98ff-6541-1e19-f7d2-366b32feded5.png)
# :penguin: SCCのAPI概要
SCCのAIアシスタントのAPIのうち、今回利用した機能について簡単に説明します。

## :secret: Authorization：
認証部分は、Webex等と同様にBearer Tokenになります。トークンはSCCのダッシュボード上で作成することができます。具体的には、Administration -> User ManagementからAPI Only Userとして作成して、Generateしたトークンをセキュアに保管します。

![API-AuthZ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/ba5f3552-e657-3a9b-f253-28b4c0a6d345.png)

SCCのAPI Authorization関連はこちらを参照
https://developer.cisco.com/docs/cisco-defense-orchestrator/getting-started/#getting-started

## :ear_tone2: Ask AI Assistant(New)：
新規クエリは、このEndpointを利用して作成します。このときの`entryUiD`が`conversationUiD`として他のAPI Endpointの引数として使うことでメッセージを抽出したり、継続質問したり出来るようになっています。逆にこのEndpointだけだと、結果は返ってこないので、別途、Get Messagesを使って取得が必要です。

![AI-Ask-new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/ea36d09a-e12e-fc02-2342-31524ccb29d6.png)

## :mailbox: Get Messages：
AIアシスタントの回答は、`ConversationUid`をキーにしてクエリすることで、contentの中で確認可能ですが、回答が出来てから抽出する必要があります。回答が出来ておれば、typeが”RESPONSE”のメッセージが出来ているので、それが出るまで適当にSleepで回す必要があります。

![AI-Get-Message.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/2f71f863-b4c9-1ac3-0e4d-370084c899bc.png)

## :ear: Ask AI Assistant(Existing Conversation)：
追加の質問は、このEndpointを利用して作成します。このとき、最初の質問で得た`entryUiD`を`conversationUiD`としてURLを構成しないと、新規の質問として扱われるので注意が必要です。

![AI-Ask-existing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866339/d43b50fb-d5f8-c0ea-d4a5-93dffd788003.png)

:::note info
ちなみにDeleteのAPIは無いので作成した質問と回答は消すことが出来ませんのでご注意下さい。
:::

SCCのAPIリファレンス
https://developer.cisco.com/docs/cisco-security-cloud-control/get-conversations/

# :penguin: プログラム簡易フロー
今回考えたプログラムは下記のフローで実装を考えました。

1. 標準入出力で日本語でインプットを受け付ける。
2. DeepL API経由で英語に翻訳する。
3. 英語のインプットをCDO AI Assistant APIに渡す。
4. 英語のアウトプットをCDO AI Assistant APIから受け取る。
5. DeepL API経由で日本語に翻訳する。

非常にシンプルですね。

# :penguin: 作成したプログラム
上記のフローに従って、コーディングしました。コーディングはVS Codeに会社からライセンス提供してもらったCopilotの機能をアドオンして実装してみました。Copilotは初めて使ったのですが、今まで細かい処理を毎回ググってコーディングしてテストしてを繰り返していたので結構簡単な処理でも実装に時間がかかっていたのですが、Copilotを使うと実装したい内容を日本語で書くと、正解に近いコードを自動で実装してくれるのが非常に便利でした。もちろん、テストして微修正は必要にはなりますが、今までのグーグル検索での作業に比べると圧倒的に早く実装出来たのではないかと思います。ぜひ、今後も(予算さえ許容されれば)サンプルプログラム作成時には活用していきたいと個人的には思いました。

## :ear: 質問するコード
質問するコード。最初の問合せかどうかは`conversationUiD`の値を見て判断。

```python
import requests
import json
import time

def query_cisco_ai_assistant(query, conversationUid):
    if conversationUid == "none":
        url = "https://edge.apj.cdo.cisco.com/api/rest/v1/ai-assistant/conversations"
    else:
        url = "https://edge.apj.cdo.cisco.com/api/rest/v1/ai-assistant/conversations/" + conversationUid
    headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization': 'Bearer <SCCで保存したトークン>'
    }
    payload = {
        "content": query
    }
    
    response = requests.post(url, json=payload, headers=headers)
    
    if response.status_code == 202:
        conversationUid = json.loads(response.text)["entityUid"]
        return conversationUid
    else:
        return {"error": "Failed to get response from Cisco AI Assistant"}

```

## :pencil: 最後のメッセージのみ表示するコード。

```python
def get_cisco_ai_assistant(conversationUid):

    url = "https://edge.apj.cdo.cisco.com/api/rest/v1/ai-assistant/conversations/" + conversationUid + "/messages"
    headers = {
      'Accept': 'application/json',
      'Content-Type': 'application/json',
      'Authorization': 'Bearer <SCCで保存したトークン>'
    }
    
    response = requests.get(url, headers=headers)
    
    while True:
        response_json = json.loads(response.text)
        if response_json[0]["type"] == "RESPONSE":
            break
        time.sleep(1)
        response = requests.get(url, headers=headers)

    return response_json

```

## :flag_us: 日本語クエリを英語に変換するコード。

```python
def translate_to_english(text):
    api_key = '<DeepLのAPIキー>'
    source_lang = 'JA'
    target_lang = 'EN'

    url = "https://api-free.deepl.com/v2/translate"
    params = {
            'auth_key' : api_key,
            'text' : text,
            'source_lang' : source_lang,
            "target_lang": target_lang
        }

    response = requests.post(url, data=params)
    if response.status_code == 200:
        return response.json()['translations'][0]['text']
    else:
        return {"error": "Failed to translate text"}
```

## :flag_jp: 英語での回答を日本語に変換するコード。

```python
def translate_to_japanese(text):
    api_key = '<DeepLのAPIキー>'
    source_lang = 'EN'
    target_lang = 'JA'

    url = "https://api-free.deepl.com/v2/translate"
    params = {
            'auth_key' : api_key,
            'text' : text,
            'source_lang' : source_lang,
            "target_lang": target_lang
        }

    response = requests.post(url, data=params)
    if response.status_code == 200:
        return response.json()['translations'][0]['text']
    else:
        return {"error": "Failed to translate text"}

```

## :xmas-tree:  メイン関数。

```python
if __name__ == "__main__":
    conversationUid = "none"
    while True:
        user_query = input("日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。): ")
        if user_query.lower() == 'stop':
            break
        user_query_en = translate_to_english(user_query)

        conversationUid = query_cisco_ai_assistant(user_query_en, conversationUid)
        if "error" in conversationUid:
            print(conversationUid["error"])
            continue
        result = get_cisco_ai_assistant(conversationUid)

        result_jp = translate_to_japanese(result[0]["content"])
        print(result_jp.replace("\\n", "\n"))

```


# :penguin: 動作確認
では、早速、動作確認した動画を見てみましょう。

動画は下記リンク
https://cisco.box.com/s/jzkd4o9tvexg5ckejun86b0e1wh50syw

出力テキストはこちら

```
> python.exe .\cdo-ai-assist.py
日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。): 今回のメジャーリーグのワールドシリーズの結果を教えて。
ご質問ありがとうございます。シスコの統合ソリューション・スイートについては、お気軽にお問い合わせください。
日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。): CDOに登録されているデバイス 情報を教えて。
CDO に登録されているデバイスの名前は FP1010 です。これは Cisco Firepower 1010E Threat Defense で、ソフトウェア・バージョンは 7.4.1 です。このデバイスには、ハードウェアの仕様、運用モード、ポリシーなどの詳細な概要が記載されています。

ポリシーの結果

# ```
日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。): FP1010に割当られているポリシーを教えて。
申し訳ありませんが、今のところお答えできません。
日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。): FP1010に割当られているACPを 教えて。
FP1010 に割り当てられたアクセスポリシーは FP1010Policy です。

ポリシー結果

# ```
日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。): FP1010Policyのルールを教えて。
FP1010Policy には、ルール番号 1 の "Allow Outbound Traffic" というルールがあります。

ポリシー結果
 {"table"：{"headers"："headers": ["#", "アクセスルール名", "ルール番号"], "rows"：[1", "Allow_Outbound_Traffic", "1"]]}}。

# ```
日本語で質問してください。 (もしくは質問をやめるときは 英語で stop と入力してください。):
```

# :penguin: 最後に
このように、少しの工夫と少しのプログラミングで、便利なAIアシスタントをさらに便利に使えるよう日本語対応が出来ました。今後出てくる他のシスコ製品のAIアシスタントも最初は日本語対応していない可能性がありますが、このプログラムを活用することで、日本語対応することが出来るのではないかと思います。

# :penguin: 免責事項

本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。