ChatGPTとDifyで実現する高度なポケモン検索機能の実装方法

![@subarashiisaito (2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/413a9957-f9df-fdae-94c4-f9d7a0cc58b3.png)

生成AIを活用した効率的な検索システムの構築は、多くのエンジニアにとって注目のトピックです。この記事では、ChatGPTとDifyを組み合わせて、ポケモンの特徴から情報を検索できる高度な機能を実装する方法を解説します。

## はじめに

生成AIと検索機能の組み合わせは、情報検索に新たな可能性をもたらしています。ChatGPTの自然言語処理能力とDifyのAIアプリケーション開発プラットフォームを活用することで、従来では難しかった特徴ベースの柔軟な検索が実現できます。

この検索システムでは、「炎タイプで物理攻撃が高いポケモン」といった自然言語での問い合わせに対して、該当するポケモンの一覧と詳細情報を返すことができます。例えば「きいろいネズミ」と入力するとピカチュウが、「出っ歯」と入力するとビーバーが検索結果として表示されます。

![名称未設定のデザイン (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/66224486-c376-8488-fef5-4bd0779a4c1d.gif)

## 宣伝

https://www.devspot.jp

クラウドソーシングサイトで活動するエンジニアの仕事探し・提案文の作成をサポートするサービスを運用しています。AIを活用して効率的に案件に応募できます。
現在Beta版につき無料でご利用できるので、エンジニアの方はぜひ使っていただけると嬉しいです！

## 実装手順

### 1. Difyの準備
1. [Dify公式ウェブサイト](https://dify.ai/jp)でアカウントを作成
2. 新規プロジェクトを作成し、「ワークフロー」タイプを選択

### 2. ワークフローの構築
システムは以下の流れで動作します：
1. ユーザーからのテキスト入力を受け取る
2. ChatGPT-4で処理
3. PythonスクリプトでポケモンAPIを実行
4. 取得した情報を出力

![スクリーンショット 2024-12-27 6.14.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/4bbb29c8-b533-dfe4-a935-8096a419bde6.png)

### 3. 各ノードの設定

**開始ノード**
- 入力フィールドとして「query」変数を設定
- フィールドタイプは「段落」を選択

![スクリーンショット 2024-12-27 4.48.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/d7782d99-aeda-a7f3-f30f-fb93146ca976.png)

**LLMノード（ChatGPT）**
- GPT-4モデルを選択
- 入力として開始ノードの「query」変数を使用
- システムプロンプトでポケモンの英語名を小文字で出力するよう設定

prompt:

```txt
Based on the information provided by the user about a pokémon, identify the English name of the pokémon. Output only the name of the pokémon in lowercase letters, without any additional information.
```

![スクリーンショット 2024-12-27 4.50.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/ecf05b66-40cb-92cd-023d-48fbd527cc45.png)


**コードノード（Python）**
- Pokemon APIを実行してポケモンの情報を取得
- 入力として前ノードのポケモン名を使用
- ポケモン名、図鑑ID、画像URLを出力

pythonのコード

```python
import requests

def get_api_data(endpoint, param):
    base_url = "https://pokeapi.co/api/v2/"
    url = f"{base_url}{endpoint}/{param}"
    response = requests.get(url)
    if response.status_code == 200:
        return response.json()
    else:
        return None

def main(pokemon_name: str) -> dict:
    pokemon_data = get_api_data("pokemon", pokemon_name)
    if pokemon_data:
        return {
            "pokemon_name": pokemon_data["name"],
            "pokemon_id": pokemon_data["id"],
            "image": pokemon_data["sprites"]["front_default"]
        }
    else:
        return {"pokemon_name": "", "pokemon_id": "", "image": ""}
```

![スクリーンショット 2024-12-27 4.55.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/bba855bc-8a5f-3eca-a632-269787bd2fee.png)


**終了ノード**
- コードノードからの出力を最終結果として設定

![スクリーンショット 2024-12-27 4.56.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3955753/fb9f9f0d-bfe1-4198-251b-cde772949e35.png)

## 応用と発展

このシステムは映画情報や商品検索など、他のデータベースにも応用可能です。音声入力対応やマルチデバイス対応を追加することで、さらに使いやすいシステムを構築できます。

## まとめ

ChatGPTとDifyを組み合わせることで、従来の検索システムでは実現できなかった柔軟な検索機能を実装できます。今後は検索履歴や好みを学習した個人化機能の追加など、さらなる発展が期待できます。

この技術は様々な分野に応用可能で、新しい可能性を切り開くものです。ぜひ自身のプロジェクトでも活用してみてください。

## 宣伝

https://www.devspot.jp

クラウドソーシングサイトで活動するエンジニアの仕事探し・提案文の作成をサポートするサービスを運用しています。AIを活用して効率的に案件に応募できます。
現在Beta版につき無料でご利用できるので、エンジニアの方はぜひ使っていただけると嬉しいです！

## DSLファイル

以下のDSLファイルをdifyにインポートすることですぐに試すことができます。
※ 以下のテキストをエディタ等を利用して~.yamlのファイル名にしてPCに保存し、それをdifyにアップロードしてください。

```yml
app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  mode: workflow
  name: ポケモンなんでも検索
  use_icon_as_answer_icon: false
kind: app
version: 0.1.5
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      allowed_file_extensions:
      - .JPG
      - .JPEG
      - .PNG
      - .GIF
      - .WEBP
      - .SVG
      allowed_file_types:
      - image
      allowed_file_upload_methods:
      - local_file
      - remote_url
      enabled: false
      fileUploadConfig:
        audio_file_size_limit: 50
        batch_count_limit: 5
        file_size_limit: 15
        image_file_size_limit: 10
        video_file_size_limit: 100
        workflow_file_upload_limit: 10
      image:
        enabled: false
        number_limits: 3
        transfer_methods:
        - local_file
        - remote_url
      number_limits: 3
    opening_statement: ''
    retriever_resource:
      enabled: true
    sensitive_word_avoidance:
      enabled: false
    speech_to_text:
      enabled: false
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
      language: ''
      voice: ''
  graph:
    edges:
    - data:
        isInIteration: false
        sourceType: code
        targetType: end
      id: 1735203250975-source-1735204092473-target
      source: '1735203250975'
      sourceHandle: source
      target: '1735204092473'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: start
        targetType: llm
      id: 1735203220001-source-1735203227329-target
      source: '1735203220001'
      sourceHandle: source
      target: '1735203227329'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        sourceType: llm
        targetType: code
      id: 1735203227329-source-1735203250975-target
      source: '1735203227329'
      sourceHandle: source
      target: '1735203250975'
      targetHandle: target
      type: custom
      zIndex: 0
    nodes:
    - data:
        desc: ''
        selected: false
        title: 開始
        type: start
        variables:
        - label: どのようなポケモンをお探しですか？
          max_length: 3000
          options: []
          required: true
          type: paragraph
          variable: query
      height: 90
      id: '1735203220001'
      position:
        x: -267.39619867346937
        y: 282
      positionAbsolute:
        x: -267.39619867346937
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        context:
          enabled: true
          variable_selector:
          - '1735203220001'
          - query
        desc: ''
        model:
          completion_params:
            temperature: 0.7
          mode: chat
          name: gpt-4
          provider: openai
        prompt_template:
        - id: c133fb31-b8e2-484b-b176-b14bd3526369
          role: system
          text: Based on the information provided by the user about a pokémon, identify
            the English name of the pokémon. Output only the name of the pokémon in
            lowercase letters, without any additional information.
        - id: 097e079c-bfee-4946-a000-85062bb426b9
          role: user
          text: '{{#1735203220001.query#}}'
        selected: false
        title: LLM
        type: llm
        variables: []
        vision:
          enabled: false
      height: 98
      id: '1735203227329'
      position:
        x: 174.8400237093134
        y: 282
      positionAbsolute:
        x: 174.8400237093134
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        code: "import requests\n\ndef get_api_data(endpoint, param):\n    base_url\
          \ = \"https://pokeapi.co/api/v2/\"\n    url = f\"{base_url}{endpoint}/{param}\"\
          \n    response = requests.get(url)\n    if response.status_code == 200:\n\
          \        return response.json()\n    else:\n        return None\n\ndef main(pokemon_name:\
          \ str) -> dict:\n    pokemon_data = get_api_data(\"pokemon\", pokemon_name)\n\
          \    if pokemon_data:\n        return {\n            \"pokemon_name\": pokemon_data[\"\
          name\"],\n            \"pokemon_id\": pokemon_data[\"id\"],\n          \
          \  \"image\": pokemon_data[\"sprites\"][\"front_default\"]\n        }\n\
          \    else:\n        return {\"pokemon_name\": \"\", \"pokemon_id\": \"\"\
          , \"image\": \"\"}"
        code_language: python3
        desc: ''
        outputs:
          image:
            children: null
            type: string
          pokemon_id:
            children: null
            type: number
          pokemon_name:
            children: null
            type: string
        selected: false
        title: コード
        type: code
        variables:
        - value_selector:
          - '1735203227329'
          - text
          variable: pokemon_name
      height: 54
      id: '1735203250975'
      position:
        x: 545.9995420088516
        y: 282
      positionAbsolute:
        x: 545.9995420088516
        y: 282
      selected: true
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    - data:
        desc: ''
        outputs:
        - value_selector:
          - '1735203250975'
          - pokemon_name
          variable: pokemon_name
        - value_selector:
          - '1735203250975'
          - pokemon_id
          variable: pokemon_id
        - value_selector:
          - '1735203250975'
          - image
          variable: pokemon_image
        selected: false
        title: 終了
        type: end
      height: 142
      id: '1735204092473'
      position:
        x: 972.3964276690433
        y: 282
      positionAbsolute:
        x: 972.3964276690433
        y: 282
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 244
    viewport:
      x: 199.41093605471602
      y: 53.77255523481003
      zoom: 0.5293865926094312
```