2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Difyのプラグインを開発する時に役に立つかもしれない情報

Posted at

はじめに

DifyはオープンソースのAIアプリ開発プラットフォームとして人気があります。

ネットワーク管理ソフトTWSNMP FC

の機能をAIから使ってもらうためにDifyのプラグインを開発しました。

このプラグインを開発した時に苦労したことを何かの役に立てばと思って紹介します。

Difyプラグインの開発

基本的な手順

公式のページに方法が詳しく書いてあります。

ツールタイプのプラグインを開発する方法は

に説明があります。

要約すると

image.png

のようになります。

開発環境

私は、ローカル環境でテストできるように

image.png

の環境で開発しました。

プラグイン開発のノウハウ

CLIを使ってプラグインプロジェクトを初期化

./dify plugin init

して自動生成されるソースコードやチュートリアルの説明にでてくるソースコードの中で、そのまま使わない方がよいポイントを紹介します。他の公式プラグインのソースコードを調べた内容です。

エラーの返し方

説明のページでは、

tools/tool.py
 if not content:
    raise Exception("公開するコンテンツは空にできません。")

のように例外でエラーを返すような書き方ですが、

/tools/do_ping.py
 if  not content:
    yield self.create_text_message("公開するコンテンツは空にできません。")

のようにLLM側へのテキストによる応答を返すほうがようさそうです。

ログの出力

# Import logging and custom handler
import logging
from dify_plugin.config.logger_format import plugin_logger_handler
# Set up logging with the custom handler
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.addHandler(plugin_logger_handler)

のようにloggerを定義したら、

        r = api.login(user,password)
        if r:
            logger.error("Can not login to TWSNMP FC")
            yield self.create_text_message(f"Can not login to TWSNMP FC: {r}")

のように、ログを出力できます。infoやdebugも指定できます。

配列の応答を返す方法

例えば、nodesがノードを示すデータの配列だった場合

        nodes = api.get("/api/nodes")
        if not nodes:
            logger.error("Failed to retrieve nodes from TWSNMP FC")
            yield self.create_text_message("Failed to retrieve nodes from TWSNMP FC")
        
        yield self.create_json_message(nodes)

のように配列を全部返すとうまくいきません。

        nodes = api.get("/api/nodes")
        if not nodes:
            logger.error("Failed to retrieve nodes from TWSNMP FC")
            yield self.create_text_message("Failed to retrieve nodes from TWSNMP FC")
        
        for node  in nodes:
            yield self.create_json_message(node)

のように配列の要素を1件づつyieldで返すとうまくいきます。

多言語対応

自動生成される設定ファイルには

provider/test.yaml
identity:
  author: "twsnmp"
  name: "test"
  label:
    en_US: "test"
    zh_Hans: "test"
    pt_BR: "test"
  description:
    en_US: "test"
    zh_Hans: "test"
    pt_BR: "test"
  icon: "icon.svg"
tools:
  - tools/test.yaml
extra:
  python:
    source: provider/test.py

のように中国語、ブラジルのポルトガル語が入っていますが、
消してen_USだけにしても問題ありませんでした。
ja_JPもいれてもよいです。

アイコンファイル

SVG形式になっていますがpngでも問題ないようです。

プライバシーポリシー

自動生成されるファイルは、

PRIVACY.md
## Privacy

!!! Please fill in the privacy policy of the plugin.

のようになっています。
特に、プラグインがユーザー情報を収集するような動作をしなければ

PRIVACY.md

# Privacy Policy

This tool is designed with privacy in mind and does not collect any user data. We are committed to maintaining your privacy and ensuring your data remains secure.

## Data Collection

- **No Personal Information**: We do not collect, store, or process any personal information.
- **No Usage Data**: We do not track or monitor how you use the tool.
- **No Analytics**: We do not implement any analytics or tracking mechanisms.

## Third-Party Services

This tool does not integrate with or utilize any third-party services that might collect user data.

## Changes to Privacy Policy

If there are any changes to our privacy practices, we will update this document accordingly.

## Contact Us

If you have any questions or concerns about this Privacy Policy, please contact us at

<連絡先メールアドレス>

でよいと思います。

GitHUBで自動公開

自動生成される.github/workflows/plugin-publish.ymlでは、自動でプラグインのパッケージを作成しますが、プルリクエストを作成するような動作になっています。自分のリポジトリでtagをPUSHした時に自動リリースするGitHUBアクションは

.github/workflows/release.yml
name: release

on:
  push:
    tags:
      - "v*"

jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Download CLI tool
        run: |
          mkdir -p $RUNNER_TEMP/bin
          cd $RUNNER_TEMP/bin

          wget https://github.com/langgenius/dify-plugin-daemon/releases/download/0.0.6/dify-plugin-linux-amd64
          chmod +x dify-plugin-linux-amd64

          echo "CLI tool location:"
          pwd
          ls -la dify-plugin-linux-amd64

      - name: Get basic info from manifest
        id: get_basic_info
        run: |
          PLUGIN_NAME=$(grep "^name:" manifest.yaml | cut -d' ' -f2)
          echo "Plugin name: $PLUGIN_NAME"
          echo "plugin_name=$PLUGIN_NAME" >> $GITHUB_OUTPUT

          VERSION=$(grep "^version:" manifest.yaml | cut -d' ' -f2)
          echo "Plugin version: $VERSION"
          echo "version=$VERSION" >> $GITHUB_OUTPUT

          # If the author's name is not your github username, you can change the author here
          AUTHOR=$(grep "^author:" manifest.yaml | cut -d' ' -f2)
          echo "Plugin author: $AUTHOR"
          echo "author=$AUTHOR" >> $GITHUB_OUTPUT

      - name: Package Plugin
        id: package
        run: |
          cd $GITHUB_WORKSPACE
          PACKAGE_NAME="${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg"
          $RUNNER_TEMP/bin/dify-plugin-linux-amd64 plugin package . -o "$PACKAGE_NAME"

          echo "Package result:"
          ls -la "$PACKAGE_NAME"
          echo "package_name=$PACKAGE_NAME" >> $GITHUB_OUTPUT

          echo "\nFull file path:"
          pwd
          echo "\nDirectory structure:"
          tree || ls -R
      - name: Release
        uses: softprops/action-gh-release@v2
        if: github.ref_type == 'tag'
        with:
          files: ${{ steps.get_basic_info.outputs.plugin_name }}-${{ steps.get_basic_info.outputs.version }}.difypkg


でいけます。

プラグインの署名

プラグインは署名していないので、Difyを

./env

FORCE_VERIFYING_SIGNATURE=false

をつけて起動しないとGitHUBから配布したプラグインをインストールできませんでした。

今後、マーケットプレイスから公開する方法をしらべようと思います。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?