今日から始めるチャット対話システムの実装

# はじめに

この記事では、初心者エンジニア向けに、Pythonを使用してルールベースのタスク指向型対話システムを構築する方法を紹介します。WindowsおよびMacのどちらのOSでも実行可能な手順になっています。

### この記事で学べること

- タスク指向型対話システムの基本

- Pythonを使った簡単な実装

- 正規表現の基礎と応用

- OpenAIのAPIを使った拡張

# タスク指向型対話システムとは

タスク指向型対話システムは、特定のタスク（例: チケット予約、商品検索、タスク管理など）を完了するためにユーザーと対話するシステムです。このシステムでは、ルールベースで応答を定義します。

例えば、以下のような会話を扱います:

>ユーザー: タスクを追加したい
システム: タスクのタイトルは何ですか？
ユーザー: 買い物
システム: タスク "買い物" を追加しました。

### 他の対話システムの例

# 必要な環境と準備

### Pythonのインストール

Pythonがインストールされていない場合は、以下からダウンロードしてインストールしてください。

Python公式サイト


#### Pythonがインストールされているかを確認

以下のコマンドをターミナル（Mac）またはコマンドプロンプト（Windows）で実行し、Pythonが正しくインストールされているか確認します。

    python --version

    python3 --version

上記のコマンドでPythonのバージョン（例: Python 3.10.4）が表示されれば、インストールされています。

もしエラーが出る場合は、Pythonのインストールを再度確認してください。

### 必要なライブラリのインストール

ターミナル（Mac）またはコマンドプロンプト（Windows）を開き、以下のコマンドを実行します。
    
    pip install prompt-toolkit

prompt-toolkitは、対話型コンソールアプリケーションを簡単に作成するためのライブラリです。

# システムの構築

### ディレクトリの準備

作業用のディレクトリを作成し、Pythonファイルを作成します。

    mkdir task_dialog_system
    cd task_dialog_system
    code dialog_system.py

(エクスプローラーやFinderから直接操作を行っても、問題ありません。)

### コードの実装

以下のコードを dialog_system.py に書き込みます。
順に追加していってください。
### ライブラリのインポート
~~~pythpn
from prompt_toolkit import PromptSession
~~~

### タスクを管理するリスト
~~~python
tasks = []
~~~

### 対話システムの関数

~~~python
    def task_dialog_system():
        session = PromptSession()
        print("タスク管理システムへようこそ！\n終了するには 'exit' と入力してください。")
    
        while True:
            user_input = session.prompt("ユーザー: ").strip()
    
            if user_input.lower() == "exit":
                print("システム: ご利用ありがとうございました！")
                break
    
            if "タスクを追加" in user_input:
                print("システム: タスクのタイトルは何ですか？")
                task_title = session.prompt("ユーザー: ").strip()
                tasks.append(task_title)
                print(f"システム: タスク '{task_title}' を追加しました。")
    
            elif "タスクを表示" in user_input:
                if tasks:
                    print("システム: 現在のタスク一覧です:")
                    for i, task in enumerate(tasks, 1):
                        print(f"  {i}. {task}")
                else:
                    print("システム: 現在タスクはありません。")
    
            else:
                print("システム: 申し訳ありません、そのコマンドは理解できませんでした。")
~~~

### 関数を呼び出す
~~~python
    if __name__ == "__main__":
        task_dialog_system()
~~~

# 実行方法

ターミナル（Mac）またはコマンドプロンプト（Windows）を開きます。

スクリプトが保存されているディレクトリに移動します。
（ここは自身の環境に合わせて文字を変えてください。）

    cd path/to/task_dialog_system

以下のコマンドを実行します。

    python dialog_system.py
    python3 dialog_system.py

システムが起動し、対話を開始できます。

# 動作確認

以下のコマンドを入力して動作を確認しましょう。

入力例

>ユーザー: タスクを追加
>システム: タスクのタイトルは何ですか？
>ユーザー: ミーティング準備
>システム: タスク 'ミーティング準備' を追加しました。
>ユーザー: タスクを表示
>システム: 現在のタスク一覧です:
>1.ミーティング準備
>ユーザー: exit
>システム: ご利用ありがとうございました！

動作が確認できたら、次は「正規表現」を用いて対話に拡張性を持たせましょう。

# 正規表現とは

正規表現（Regular Expression）は、文字列のパターンを表現するための方法です。特定の文字列や文字列のパターンを効率的に検索、置換、マッチングするために使用されます。

### 正規表現の基本構文の例
|header1|header2|
|:--:| :--|
| . | 任意の1文字 |
| * | 直前の文字が0回以上繰り返される |
+| 直前の文字が1回以上繰り返される
?| 直前の文字が0回または1回現れる
[]| 文字クラス。(例: [a-z] は小文字アルファベットの範囲)

Pythonでは、reモジュールを使用して正規表現を操作できます。

# 正規表現を用いた認識の拡張

現状のシステムでは、単純なキーワードマッチングでコマンドを判別しています。ここでは正規表現を用いて、ユーザーの入力をより柔軟に解釈できるよう改良します。

### 正規表現を用いたコードの修正

以下のコードを使い、reモジュールを利用して入力の判定を行います。

~~~python
import re
from prompt_toolkit import PromptSession

# タスクを管理するリスト
tasks = []

# 対話システムの関数
def task_dialog_system():
    session = PromptSession()
    print("タスク管理システムへようこそ！\n終了するには 'exit' と入力してください。")

    while True:
        user_input = session.prompt("ユーザー: ").strip()

        if re.match(r"(?i)exit", user_input):
            print("システム: ご利用ありがとうございました！")
            break

        if re.search(r"(?i)(タスクを追加|新しいタスク)", user_input):
            print("システム: タスクのタイトルは何ですか？")
            task_title = session.prompt("ユーザー: ").strip()
            tasks.append(task_title)
            print(f"システム: タスク '{task_title}' を追加しました。")

        elif re.search(r"(?i)タスクを表示|タスク一覧", user_input):
            if tasks:
                print("システム: 現在のタスク一覧です:")
                for i, task in enumerate(tasks, 1):
                    print(f"  {i}. {task}")
            else:
                print("システム: 現在タスクはありません。")

        else:
            print("システム: 申し訳ありません、そのコマンドは理解できませんでした。")

if __name__ == "__main__":
    task_dialog_system()
~~~

### 動作確認
実際に作成したコードを実行し、どのように動作が変化したか試してみましょう。

# OpenAI APIを使用した雑談機能の追加

最後に、OpenAIのAPIを利用して、タスク指向の対話以外にも雑談ができる機能を追加します。

[Open AI API設定]( https://auth.openai.com/authorize?audience=https%3A%2F%2Fapi.openai.com%2Fv1&auth0Client=eyJuYW1lIjoiYXV0aDAtc3BhLWpzIiwidmVyc2lvbiI6IjEuMjEuMCJ9&client_id=DRivsnm2Mu42T3KOpqdtwB3NYviHYzwD&device_id=a5ae9c7f-c68a-4569-b058-e233b9b9e2b5&issuer=https%3A%2F%2Fauth.openai.com&max_age=0&nonce=QzB0MFlNM0pDZEE1cXB5cThQcGwzZ3VrQTNDVF8xTXI4RDhkTHF0OVg2WA%3D%3D&redirect_uri=https%3A%2F%2Fplatform.openai.com%2Fauth%2Fcallback&response_mode=query&response_type=code&scope=openid+profile+email+offline_access&screen_hint=signup&state=bnFnNklrfnRkMlVuVDlqaUVQcWtjc3NudH5HTXVucDkuTThrUUJjS3JySA%3D%3D&flow=treatment )

### OpenAI APIの設定

OpenAIの公式サイトでAPIキーを取得してください。
[参考にさせていただいたサイト]( https://qiita.com/kurata04/items/a10bdc44cc0d1e62dad3 )


必要なライブラリをインストールします。
~~~
pip install openai
~~~
### コードの実装

以下のコードを既存のシステムに追加します。
~~~python
import openai

# OpenAIのAPIキーを設定
openai.api_key = "YOUR_API_KEY"

def get_chat_response(user_input):
    try:
        response = openai.Completion.create(
            engine="text-davinci-003",
            prompt=user_input,
            max_tokens=150
        )
        return response.choices[0].text.strip()
    except Exception as e:
        return "エラーが発生しました: " + str(e)
~~~

### システムへの統合

対話システムのループ内に以下を追加します。
~~~python
else:
            print("システム: タスク外の会話を検出しました。雑談モードに切り替えます。")
            chat_response = get_chat_response(user_input)
            print(f"システム: {chat_response}")
~~~

これで、タスク管理と雑談の両方を行える対話システムが完成しました。
プロンプトの設定なども行い、自由度の高い対話に挑戦してみましょう。

# 発展とカスタマイズ
ここでは基本的なチャット型対話システムの実装を行いました。
今回作成したコードをベースに、自身の作りたい対話システムに発展させていきましょう。

### 対話システムの要素の例
チャット型に限定した対話システムでも、様々な発展の要素があります。
カスタマイズ可能な要素の例をまとめておきます。

#### 達成すべき目的の有無
- タスク指向型対話システム
    - 目標（タスク）の達成のためにユーザと対話を行う。
- 雑談対話システム（非タスク指向型対話システム）
    - 目標（タスク）持たずにユーザと対話を行う。

#### 対話のドメイン
- クローズドドメイン
    - 話題（ドメイン）を限定した対話を行う。
    - 一つの話題に対話を行う**シングルドメイン対話システム**
    - 複数の話題に対話を行う**マルチドメイン対話システム**
- オープンドメイン
    - どのような話題に対してでも対話を行う。

#### 交替に関しての工夫
- どのようなタイミングで話し出すのか？（例）
    - **タイマー**のように決まった時間で話し出す
    - **視線**などのユーザの挙動に反応して話し出す
- どのようなタイミングで話す人を交代するの交替するのか？（例）
    - 相手が黙ったら自動でシステムが応答をする
    - ユーザがボタンを押すまで話を聞き続ける

などなど


# 終わりに

今回は、今日からモノ造りを始めた人に向けて、基本的なチャット型対話システムの作成と発展についてまとめました。
対話には様々な形式とシステムの工夫があるので、きになった要素やキーワードはぜひ検索してみてください。