WindowsでDifyを使いこなす!

スクラップの目次
1.Dify環境を作る/アップデートする
-
Dify環境を作る #1 2024-06-04
- 社内PCでDifyを起動させるためにdocker-compose.yamlを修正した
-
Dify環境を作る #2 2024-06-15
- 別のPCでは、wsl2データを全削除したらエラー解消した
-
Difyを0.6.10にアップデートする 2024-06-09
- やはり公式のdocker-compose.yamlを修正した
-
Difyを0.6.10から0.6.12fix1にアップデートする 2024-07-12
- データ引継ぎは断念。。
-
Dify0.6.12fix1から0.6.14にアップデートする 2024-07-31
- データ継承も問題なくできた。
-
Dify0.6.15から0.7.0にアップデートする 2024-09-20
- データ継承も問題なくできた。
-
Difyを0.8.3にアップデートする 2024-09-25
- アップデートは問題なくできた。LLMモデルのロードバランサー機能もONにした。
- ただローカルホストしているFirecrawlのツールが使えなくなった。Firecrawlによるナレッジ取得はできるので、Firecrawlコンテナとの通信はできている、、続く。
-
Difyを0.10.0にアップデートする 2024-10-23
- ファイルアップロード機能が追加された。
-
Dify0.11.0にアップデートする 2024-11-15
- 並列イテレーションができるようになった!
-
Dify v1.4.0をセルフホストする 2025-05-18
- ようやくv1をセルフホストできた。
2.トラブル対応
-
ベクトルデータベースとの接続トラブル対処記録 2024-07-31
- weaviateデータベースに接続できなくなったが、middlewareを再起動したら解決した。
-
Dify0.9.0でRAG検索できないエラー発生 2024-10-02
- 0.9.1にアップデートしたら直りました。
3.DifyをAPI操作する/Difyに外部から接続する
-
DifyアプリにAPIアクセスする 2024-06-11
- 公式docを参考にしてできた
-
API経由でナレッジを操作する 2024-07-19
- Pythonのrequestsライブラリを使う
-
DifyコンテナのPostgresデータベースにSQLツールから接続する 2024-07-16
- A5:SQL Mk-2から接続する。
-
チャットアプリAPIをまとめる 2024-12-01
- 全ての機能をPythonコードにした。
-
ワークフローアプリAPIをまとめる 2024-12-30
- 全ての機能をPythonコードにした。
4.Difyと外部ツールを連携させる
-
Difyと一緒にOllamaもDockerで動かしてみる 2024-06-09
- OllamaがCPUだけで動くので遅くなった。(対処方法はある)
-
FireCrawlをセルフホストして、Difyで使う#1 2024-07-09
- 簡単にできた。社内SPOサイトはクロールできなかった。。
-
Firecrawlをセルフホストして、Difyで使う #2 2024-08-19
- Dify0.7.0にアップデートしてからツールがtextでなくjsonを出力するようになったので対応した。
-
セルフホストしているFirecrawlをv0からv1にアップデートする 2024-11-13
- Dify0.8.3にしたらツールが使えなくなったのでFirecrawlもv0からv1アップデートしたが解決せず、、続く。
-
Firecrawlをアップデートする 2024-12-24
- 備忘録です。
-
LangFuseをセルフホストして、Difyで使う #1 2024-07-08
- セルフホストはできたがhttpsでないとDifyと連携できない。。
5.Difyアプリを作る
-
Dify+Ollamaでチャットボットを作る 2024-06-09
- 英語で回答しがちなLlama3にぜったい日本語で回答させることに成功
- [Dify+OllamaでRAGチャットボットを作る#1] (https://zenn.dev/link/comments/95ccb074eac6a9) 2024-06-15
- Ollmaで使える埋め込みモデルでは日本語埋め込みできないと分かった。。
-
Dify+OllamaでRAGチャットボットを作る#2 2024-06-15
- 多言語対応埋め込みモデルを使って成功。ただし精度は悪く、実用には堪えない
-
DifyアプリとAPI連携したstreamlitチャットボットを作る 2024-12-28
- 画像とのチャットもできた。
Dify公式リンク
- Dify公式サイト ※日本語版があった
- Difyリポジトリ
- Dify公式Xアカウント
- Dify公式YouTubeチャンネル
-
Dify公式Discordサーバ
- Chrome拡張機能「Chromeの右クリックを有効にする」 ※これを入れておくとページ翻訳ができて便利
Dify関連記事を探す
その他リンク

Dify環境を作る #1
ゴール
- DifyをWindows PCにインストールして起動する
まとめ
- 公式ドキュメントとか巷にあふれるブログ記事のように簡単に起動できなかった
- 情報がなく苦労したこと
- Docker Desktop for Windows: バイパスproxy設定
- docker-compose.yaml: エラー回避のためのコード修正
関連リンク
- Dify公式doc Docker Compose Deployment
- wsl2の有効化
- MS Learn WSLの基本的なコマンド
- MS Learn WSL を使用して Windows に Linux をインストールする方法
- Docker Desktop for Windows
大まかな手順
- Docker Desktop for Windowsを導入する
- Docker環境でDifyを起動する
もう少し詳しい手順
- gitをインストールする(割愛)
- WSL2を有効化する
- 「Windowsの機能の有効化または無効化」を開いて「Linux用Windowsサブシステム」と「仮想マシンプラットフォーム」にチェックを入れて保存、PCを再起動する
設定画面
- PowerShellを管理者モードで立ち上げてubuntuをインストールする
以下のコマンドを順番に実行する。
# wslが有効になっていて、バージョン2になっていることを確認
wsl --status
# wslをアップデート
wsl --update
# インストールできるUbuntu一覧を表示
wsl --list --online
# Ubuntu-24.04をインストール
wsl --install -d Ubuntu-24.04
# インストールできたか確認
wsl -l -v
# wslを起動して、ユーザー名とパスワードを設定
wsl
- Docker Desktop for Windowsをインストールする(割愛)
- Docker Desktop for Windowsの設定をする
Docker Desktop for WindowsのResources設定画面
- wsl2との連携をONにする
- Dockerのデフォルトネットワークサブネット。Dockerコンテナ同士の通信や、ホストマシンとDockerコンテナの間の通信用(いじらない)
- プロキシ設定画面 大事!!
- バイパスproxy設定の方法が分からない場合は、
ipconfig /all
の結果をChatGPTに貼り付けて、「Docker Desktop fow Windowsのバイパスproxy設定を教えて」と言って教えてもらう! - /22 とか /24の意味は「IPv4アドレス32ビット長のうち、ネットワーク部分が何ビットかを指すか」ということ。/22だとネットワークが22ビット、ホストが10ビット(=1024)なので、1024個のIPアドレス範囲を指すことになる。(、、、とChatGPTが教えてくれた)
- Difyのコードを公式リポジトリからダウンロードする
git clone https://github.com/langgenius/dify.git
- cloneしたdifyフォルダの中のdockerフォルダでPowerShellを起動して、DifyのDockerコンテナを起動する ⇒エラーが出る
docker compose up -d
⇒port80は別のアプリですでに使われているというエラーが出る
port80を使っているのはsystem
⇒netstat -nano
コマンドでPID4のプロセスと分かる
⇒タスクマネージャーでSystemが使っていると分かる
⇒port80を使うのは諦める。
- port80でなく8080を使うように、
docker-compose.yaml
を修正する
docker-compose.yamlの修正部分
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
- ./nginx/conf.d:/etc/nginx/conf.d
#- ./nginx/ssl:/etc/ssl
depends_on:
- api
- web
ports:
# - "80:80" #元の設定
- "8080:80" #変更後の設定
#- "443:443"
- あらためて
docker-compose up -d
する ⇒まだ駄目
⇒langgenius/dify-web:0.6.9
とpostgres:15-alpine
のコンテナが停止、再起動を繰り返す。。
該当するコード
web:
image: langgenius/dify-web:0.6.9
restart: always
environment:
CONSOLE_API_URL: ''
APP_API_URL: ''
SENTRY_DSN: ''
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: postgres
POSTGRES_PASSWORD: difyai123456
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- ./volumes/db/data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
-
ChatGPTに助けてもらいながら、docker-compose.yamlをあちこち修正する。
「エラーlogを渡す⇒yamlファイルの修正案をもらう⇒トライ」を繰り返した。。
⇒最終的にできたyamlファイルはこれ
ようやく完成したdocke-compose.yamlファイル
version: '3'
# ===========================================================
services:
# -----------------------------------------------------------
api:
image: langgenius/dify-api:0.6.9
restart: always
environment:
MODE: api
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
CONSOLE_WEB_URL: ''
INIT_PASSWORD: ''
CONSOLE_API_URL: ''
SERVICE_API_URL: ''
APP_WEB_URL: ''
FILES_URL: ''
FILES_ACCESS_TIMEOUT: 300
MIGRATION_ENABLED: 'true'
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_USE_SSL: 'false'
REDIS_DB: 0
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
WEB_API_CORS_ALLOW_ORIGINS: '*'
CONSOLE_CORS_ALLOW_ORIGINS: '*'
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3_SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
SENTRY_DSN: ''
SENTRY_TRACES_SAMPLE_RATE: 1.0
SENTRY_PROFILES_SAMPLE_RATE: 1.0
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
CODE_EXECUTION_ENDPOINT: "http://sandbox:8194"
CODE_EXECUTION_API_KEY: dify-sandbox
CODE_MAX_NUMBER: 9223372036854775807
CODE_MIN_NUMBER: -9223372036854775808
CODE_MAX_STRING_LENGTH: 80000
TEMPLATE_TRANSFORM_MAX_LENGTH: 80000
CODE_MAX_STRING_ARRAY_LENGTH: 30
CODE_MAX_OBJECT_ARRAY_LENGTH: 30
CODE_MAX_NUMBER_ARRAY_LENGTH: 1000
SSRF_PROXY_HTTP_URL: 'http://ssrf_proxy:3128'
SSRF_PROXY_HTTPS_URL: 'http://ssrf_proxy:3128'
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
# -----------------------------------------------------------
worker:
image: langgenius/dify-api:0.6.9
restart: always
environment:
CONSOLE_WEB_URL: ''
MODE: worker
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_DB: 0
REDIS_USE_SSL: 'false'
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3 SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
# -----------------------------------------------------------
web:
image: langgenius/dify-web:0.6.9
restart: always
environment:
CONSOLE_API_URL: ''
APP_API_URL: ''
SENTRY_DSN: ''
networks:
- ssrf_proxy_network # 修正: defaultネットワークにssrf_proxy_networkを追加
- default
# -----------------------------------------------------------
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: postgres
POSTGRES_PASSWORD: difyai123456
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- postgres_data:/var/lib/postgresql/data # 修正: ./volumes/db/dataからpostgres_dataに変更
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
networks:
- default
# -----------------------------------------------------------
redis:
image: redis:6-alpine
restart: always
volumes:
# - redis_data:/data # 修正: ./volumes/redis/dataからredis_dataに変更
- ./volumes/redis/data:/data
command: redis-server --requirepass difyai123456
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
networks:
- default
# -----------------------------------------------------------
weaviate:
image: semitechnologies/weaviate:1.19.0
restart: always
volumes:
- ./volumes/weaviate:/var/lib/weaviate
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
CLUSTER_HOSTNAME: 'node1'
AUTHENTICATION_APIKEY_ENABLED: 'true'
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
networks:
- default
# -----------------------------------------------------------
sandbox:
image: langgenius/dify-sandbox:0.2.0
restart: always
environment:
API_KEY: dify-sandbox
GIN_MODE: 'release'
WORKER_TIMEOUT: 15
ENABLE_NETWORK: 'true'
HTTP_PROXY: 'http://ssrf_proxy:3128'
HTTPS_PROXY: 'http://ssrf_proxy:3128'
volumes:
- ./volumes/sandbox/dependencies:/dependencies
networks:
- ssrf_proxy_network
# -----------------------------------------------------------
ssrf_proxy:
image: ubuntu/squid:latest
restart: always
volumes:
- ./volumes/ssrf_proxy/squid.conf:/etc/squid/squid.conf
networks:
- ssrf_proxy_network
- default
# -----------------------------------------------------------
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- api
- web
ports:
- "8080:80"
networks:
- default # 修正: defaultネットワークを追加
# ===========================================================
networks:
ssrf_proxy_network:
driver: bridge
internal: true
default: # 修正: defaultネットワークを追加
driver: bridge
# ===========================================================
volumes:
postgres_data: # 追加: 新しいボリュームを定義
# redis_data: # 追加: 新しいボリュームを定義```
オリジナルと最終的なdocker-compose.yamlを可視化して比較
※graphvizで可視化してみた。
オリジナル
最終版
- ようやくDifyが起動!

Dify環境を作る#2
ゴール
- DIfyを別のWindows PCにインストールして起動する
まとめ
- Docker Desktopでwsl2データを全削除したらエラーが解消した
関連リンク
- エラー対処方法で参考にした記事
- [docker-compose up で failed to mkdir]((https://zenn.dev/nw/scraps/6e8ef6361f8369)
手順
※ 同じ社内ネットワークにある別のPCなので、途中までは [前回](https://zenn.dev/link/comments/59a67f0070ba23) と同じで、手順6で出たエラーだけが違う
- gitをインストール(割愛)
- wsl2を有効化(割愛)
- Docker Desktop for Windowsを導入(割愛)
- Difyのコードを公式リポジトリからgit cloneする(割愛)
- cloneしたdifyフォルダの中の
docker-compose.yaml
を書き替える
ファイルのパスはE:\dify\docker\docker-compose.yaml
書き替えたあとのdocker-compose.yaml
version: '3'
# ===========================================================
services:
# -----------------------------------------------------------
api:
image: langgenius/dify-api:0.6.9
restart: always
environment:
MODE: api
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
CONSOLE_WEB_URL: ''
INIT_PASSWORD: ''
CONSOLE_API_URL: ''
SERVICE_API_URL: ''
APP_WEB_URL: ''
FILES_URL: ''
FILES_ACCESS_TIMEOUT: 300
MIGRATION_ENABLED: 'true'
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_USE_SSL: 'false'
REDIS_DB: 0
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
WEB_API_CORS_ALLOW_ORIGINS: '*'
CONSOLE_CORS_ALLOW_ORIGINS: '*'
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3_SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
SENTRY_DSN: ''
SENTRY_TRACES_SAMPLE_RATE: 1.0
SENTRY_PROFILES_SAMPLE_RATE: 1.0
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
CODE_EXECUTION_ENDPOINT: "http://sandbox:8194"
CODE_EXECUTION_API_KEY: dify-sandbox
CODE_MAX_NUMBER: 9223372036854775807
CODE_MIN_NUMBER: -9223372036854775808
CODE_MAX_STRING_LENGTH: 80000
TEMPLATE_TRANSFORM_MAX_LENGTH: 80000
CODE_MAX_STRING_ARRAY_LENGTH: 30
CODE_MAX_OBJECT_ARRAY_LENGTH: 30
CODE_MAX_NUMBER_ARRAY_LENGTH: 1000
SSRF_PROXY_HTTP_URL: 'http://ssrf_proxy:3128'
SSRF_PROXY_HTTPS_URL: 'http://ssrf_proxy:3128'
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
# -----------------------------------------------------------
worker:
image: langgenius/dify-api:0.6.9
restart: always
environment:
CONSOLE_WEB_URL: ''
MODE: worker
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_DB: 0
REDIS_USE_SSL: 'false'
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3 SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
# -----------------------------------------------------------
web:
image: langgenius/dify-web:0.6.9
restart: always
environment:
CONSOLE_API_URL: ''
APP_API_URL: ''
SENTRY_DSN: ''
networks:
- ssrf_proxy_network # 修正: defaultネットワークにssrf_proxy_networkを追加
- default
# -----------------------------------------------------------
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: postgres
POSTGRES_PASSWORD: difyai123456
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- postgres_data:/var/lib/postgresql/data # 修正: ./volumes/db/dataからpostgres_dataに変更
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
networks:
- default
# -----------------------------------------------------------
redis:
image: redis:6-alpine
restart: always
volumes:
# - redis_data:/data # 修正: ./volumes/redis/dataからredis_dataに変更
- ./volumes/redis/data:/data
command: redis-server --requirepass difyai123456
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
networks:
- default
# -----------------------------------------------------------
weaviate:
image: semitechnologies/weaviate:1.19.0
restart: always
volumes:
- ./volumes/weaviate:/var/lib/weaviate
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
CLUSTER_HOSTNAME: 'node1'
AUTHENTICATION_APIKEY_ENABLED: 'true'
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
networks:
- default
# -----------------------------------------------------------
sandbox:
image: langgenius/dify-sandbox:0.2.0
restart: always
environment:
API_KEY: dify-sandbox
GIN_MODE: 'release'
WORKER_TIMEOUT: 15
ENABLE_NETWORK: 'true'
HTTP_PROXY: 'http://ssrf_proxy:3128'
HTTPS_PROXY: 'http://ssrf_proxy:3128'
volumes:
- ./volumes/sandbox/dependencies:/dependencies
networks:
- ssrf_proxy_network
# -----------------------------------------------------------
ssrf_proxy:
image: ubuntu/squid:latest
restart: always
volumes:
- ./volumes/ssrf_proxy/squid.conf:/etc/squid/squid.conf
networks:
- ssrf_proxy_network
- default
# -----------------------------------------------------------
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- api
- web
ports:
- "8080:80"
networks:
- default # 修正: defaultネットワークを追加
# ===========================================================
networks:
ssrf_proxy_network:
driver: bridge
internal: true
default: # 修正: defaultネットワークを追加
driver: bridge
# ===========================================================
volumes:
postgres_data: # 追加: 新しいボリュームを定義
# redis_data: # 追加: 新しいボリュームを定義 ```
オリジナルと最終的なdocker-compose.yamlを可視化して比較
※graphvizで可視化してみた。
オリジナル
最終版
- dockerフォルダでPoserShellを立ち上げて
docker-compose up -d
コマンドを打つ ⇒エラーが出る
Error response from daemon: error while creating mount source path '/run/desktop/mnt/host/e/dify/docker/volumes/sandbox/dependencies': mkdir /run/desktop/mnt/host/e: file exists
- データをいったん全削除する
GhatGPTに聞きながら対応しても解決しない
⇒ググって、この記事を見つける!
⇒同じようにやってみる
Docker Desktop for Windows操作の画面キャプチャ
Troubleshootを開く
Clean / Purge data をクリック
WSL 2を選択して delete をクリック
images も containers も全部消えた。。
- あらためて
docker-compose up -d
する - ようやくDifyが起動!

Difyを0.6.10にアップデートする
ゴール
- Dify0.6.9 から Dify0.6.10 にアップデートする
まとめ
- Dify0.6.9をインストールしたときに作ったdocker-compose.yamlファイルを流用した
関連リンク
- Dify公式リポジトリ
- Dify公式doc
手順
- いまの
docker
フォルダにあるdocker-compose.yaml
の名称をdocker-compose_069backup.yaml
みたいな名前にしておいて、公式docどおりに進める。
# dockerフォルダに移動
cd dify/docker
# リモートリポジトリのmainブランチから最新バージョンをダウンロード
git pull origin main
# 現在のdockerコンテナを停止
docker compose down
# docker-compose.ymlで定義された最新のイメージを取得
docker compose pull
# ------ ここから先はまだしない! --------------
# dockerコンテナを再構築して起動
# docker compose up -d
- 0.6.10バージョンのdocker-compose.yamlを以下のように書き換える。
docker-compose.yamlの中身
services:
api:
image: langgenius/dify-api:0.6.10
restart: always
environment:
MODE: api
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
CONSOLE_WEB_URL: 'http://161.93.***.***:8080' #追加(PCの静的IPを入れる)
INIT_PASSWORD: ''
CONSOLE_API_URL: 'http://161.93.***.***:8080' #追加(PCの静的IPを入れる)
SERVICE_API_URL: 'http://161.93.***.***:8080' #追加(PCの静的IPを入れる)
APP_WEB_URL: 'http://161.93.***.***:8080' #追加(PCの静的IPを入れる)
FILES_URL: 'http://161.93.***.***:8080' #追加(PCの静的IPを入れる)
FILES_ACCESS_TIMEOUT: 300
MIGRATION_ENABLED: 'true'
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_USE_SSL: 'false'
REDIS_DB: 0
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
WEB_API_CORS_ALLOW_ORIGINS: '*'
CONSOLE_CORS_ALLOW_ORIGINS: '*'
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3_SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
SENTRY_DSN: ''
SENTRY_TRACES_SAMPLE_RATE: 1.0
SENTRY_PROFILES_SAMPLE_RATE: 1.0
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
CODE_EXECUTION_ENDPOINT: "http://sandbox:8194"
CODE_EXECUTION_API_KEY: dify-sandbox
CODE_MAX_NUMBER: 9223372036854775807
CODE_MIN_NUMBER: -9223372036854775808
CODE_MAX_STRING_LENGTH: 80000
TEMPLATE_TRANSFORM_MAX_LENGTH: 80000
CODE_MAX_STRING_ARRAY_LENGTH: 30
CODE_MAX_OBJECT_ARRAY_LENGTH: 30
CODE_MAX_NUMBER_ARRAY_LENGTH: 1000
SSRF_PROXY_HTTP_URL: 'http://ssrf_proxy:3128'
SSRF_PROXY_HTTPS_URL: 'http://ssrf_proxy:3128'
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
worker:
image: langgenius/dify-api:0.6.10
restart: always
environment:
CONSOLE_WEB_URL: ''
MODE: worker
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_DB: 0
REDIS_USE_SSL: 'false'
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3_SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
web:
image: langgenius/dify-web:0.6.10
restart: always
environment:
CONSOLE_API_URL: ''
APP_API_URL: ''
SENTRY_DSN: ''
networks: #追加
- ssrf_proxy_network #追加
- default #追加
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: postgres
POSTGRES_PASSWORD: difyai123456
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
#- ./volumes/db/data:/var/lib/postgresql/data
- postgres_data:/var/lib/postgresql/data #変更
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
networks: #追加
- default #追加
redis:
image: redis:6-alpine
restart: always
volumes:
- ./volumes/redis/data:/data
command: redis-server --requirepass difyai123456
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
networks: #追加
- default #追加
weaviate:
image: semitechnologies/weaviate:1.19.0
restart: always
volumes:
- ./volumes/weaviate:/var/lib/weaviate
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
CLUSTER_HOSTNAME: 'node1'
AUTHENTICATION_APIKEY_ENABLED: 'true'
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
networks: #追加
- default #追加
sandbox:
image: langgenius/dify-sandbox:0.2.1
restart: always
environment:
API_KEY: dify-sandbox
GIN_MODE: 'release'
WORKER_TIMEOUT: 15
ENABLE_NETWORK: 'true'
HTTP_PROXY: 'http://ssrf_proxy:3128'
HTTPS_PROXY: 'http://ssrf_proxy:3128'
SANDBOX_PORT: 8194
volumes:
- ./volumes/sandbox/dependencies:/dependencies
networks:
- ssrf_proxy_network
ssrf_proxy:
image: ubuntu/squid:latest
restart: always
volumes:
- ./volumes/ssrf_proxy/squid.conf:/etc/squid/squid.conf
networks:
- ssrf_proxy_network
- default
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- api
- web
ports:
- "8080:80" #80:80から変更
networks: #追加
- default #追加
networks:
ssrf_proxy_network:
driver: bridge
internal: true
default: #追加
driver: bridge
volumes: #追加
postgres_data: #追加
docker-compose.yamlの中身を可視化
※streamlit+graphvizで可視化してみた。
- あたらめて起動
# dockerコンテナを再構築して起動
# docker compose up -d
- 無事起動!

Dify+Ollamaでチャットボットを作る
ゴール
- Ollamaで動くLlama3と連携したチャットボットを作る
まとめ
- Difyはすごい!
- ノーコードでLLMアプリを作れる
- 作ったアプリをホストしてくれる
- デバッグがしやすい
- ログ管理やセッション管理までできる
- LLMブロックを3段階重ねて、なんとかLlama3で日本語チャットができるようになった
参考リンク
- Dify公式doc Quickstart
- Ollama公式doc
手順
まず、DifyにOllamaで動くLlama3を登録する
- Ollamaを以下のbatファイルから起動する
※ 前提:ollamaにllama3がインストールされている
※ OLLAM_HOSTをシステム環境変数として登録してもよい
@echo off
set OLLAMA_HOST=0.0.0.0:11434
ollama serve
- Difyを起動して、アクセスする。(私の場合は
http://localhost:8080/apps
) - LLMモデルを登録する
つぎに、Difyでチャットボットを作る
- 下図のようにはじめる
スタジオ
→最初から作成
→チャットボット
→Chatflow
→アプリ名はLlama3チャットボット
- ブロックを追加、連結、編集していく。
完成したフロー
全体フロー
日→英翻訳:ユーザー入力を英語に変換する
- システムプロンプト
# INSTRUCTIONS
- Translate only the Japanese parts of the "USER INPUT" sentences into English.
- Output only the translated text.
- Do not include "Here is the translation of the Japanese part: " at the beginning of the output text.
- Ensure the translation captures the full meaning of the Japanese text without adding unnecessary context.
# GOOD SAMPLE
- USER INPUT: "moonshot meanってどういう意味?"
- YOUR OUTPUT: "What does moonshot mean?"
# BAD SAMPLE
- USER INPUT: "テニスのルールを教えて"
- YOUR OUTPUT: "Translation of Japanese text to English\nThe translation of the Japanese text is as follows:\n\n\"Teaching tennis rules\"
# USER INPUT
{{#context#}}
メインブロック:回答を生成する
英→日翻訳:LLM出力を日本語に翻訳する
システムプロンプト
以下の文章を、忠実に日本語に翻訳して出力してください。
(ただし以下は日本語に変換しないこと:固有名詞、技術用語、プログラミングコード、製品名やブランド名、特定の業界用語や略語(例えば、IT業界の「API」や「SQL」など)、ファイル名やディレクトリ名、設定や構成項目の名前、ログメッセージやエラーメッセージ、数値や特定の単位(例えば、「GB」や「Hz」など)、メールアドレスやURL )
# 翻訳する文章
{{#context#}}
出力:出力するだけ
- デバッグしながら、プロンプトやLLM設定(tempretureなど)を調整する
デバッグの様子
- アプリとして「公開する」
アプリを公開
アプリを実行
を選択すると、webアプリページが開く。
Chrome拡張機能を使って、ウェブサイトに埋め込むこともできる
※動かないサイトも多い
- アプリ管理機能もある
アプリ管理機能
ログ&アナウンス
概要
メッセージ数、アクティブユーザー数、セッション数、トークン出力速度、トークン使用量など
- (追加)最初のメッセージを設定する
最初のメッセージを設定

Dify+OllamaでRAGチャットボットを作る#1
ゴール
- OllamaのモデルだけでRAGチャットボットを作れるようになる
まとめ
- Ollamaで使える埋め込みモデルの日本語処理性能が悪い!→使えないので中止
関連リンク
埋め込みモデルの設定方法
- Dify公式: Ollamaとの連携方法
Ollamaで使える埋め込みモデル一覧(2024-6-9時点)
-
Ollamaモデル一覧
- nomic-embed-text:埋め込み可能な最大コンテキストサイズは8192トークン
- mxbai-embed-large:同512トークン
- all-minilm:同256トークン
- snowflake-arctic-embed:同4096トークン
- Ollamaブログ:埋め込みモデル
mxbai-embed-largeモデルについて
-
Ollamaでのモデル紹介
2024 年 3 月現在、このモデルは MTEB 上の Bert の大規模モデルで SOTA パフォーマンスを達成しています。OpenAI のtext-embedding-3-largeモデルなどの商用モデルよりも優れており、その 20 倍のサイズのモデルのパフォーマンスに匹敵します。 - mixedbread.aiのブログ記事
- Hugging Faceのリポジトリ
サンプルFAQデータセット
手順
Difyにmxbai-embe-largeを登録する
- ollamaにモデルをpullする。
ollama pull mxbai-embed-large
- ollamaを起動する
@echo off
set OLLAMA_HOST=0.0.0.0:11434
ollama serve
- Difyでモデルを設定する
画面右上のアカウント名
をクリック →モデルプロバイダー
→Ollama
→Add model
モデル設定画面
※ model context sizeは公式サイト(下図)を参考に、512に設定した。
埋め込むデータを準備する
- LINEヤフーが公開している「子育てAIチャットボット用FAQデータセット」を利用する
- このサイトからZIPファイルをダウンロードして展開する
解凍したデータ
エクセル(xlsx)ファイルで、レコード数は981。
質問項目は以下のとおり。
- 母子手帳・妊婦健診
- 子どもの健診
- 予防接種
- 引っ越し手続き
- 児童手当
- 療育医療・育成医療・養育医療
- 保育園・延長保育・一時保育
- 子育て支援・イベント
- その他の手続き(住民票、婚姻届など)
データを埋め込む
-
システムモデル設定
で、埋め込みモデルをmxdbai-embed-large
に設定しておく。
-
Difyに取り込む
画面上部のナレッジ
→知識を作成
→テキストファイルからインポート
→回答したエクセルファイルをアップロードと進む(詳細は下記)
ファイルアップロードから埋め込みまでの流れ
ファイルをアップロード
テキストの前処理とクリーニング
すべて自動でおまかせする。
埋め込みの実行
1分くらいで終わる。
- 検索テストをしてみる
画面上部→ナレッジ
→埋め込み完了したデータセットを選択→サイドバーの検索テスト
をクリック
検索テストの結果
※top-Kは10に再設定した
- 「母子手帳」で検索 →ダメ
- 「児童手当」で検索 →ダメ
- 「保育園に入れたい」で検索 →ダメ
→全然ダメだ。。
比較:azure-openai text-embedding-3-largeで埋め込んだときの検索テスト結果
検索テスト結果
※top-Kは6に再設定した
- 「母子手帳」で検索 →合格
- 「児童手当」で検索 →合格
- 「保育園に入れたい」で検索 →合格
→非常に優秀
別のモデル(nomic-embe-text、snowflake-arctic-embed)も導入する
- Ollamaを停止
- 二つのモデルをpull
ollama pull nomic-embed-text
ollama pull snowflake-arctic-embed
- Ollmaを再起動
- Difyと連携
-
Model context size
はnomic-embed-text
は8192
、snowflake-arctic-embed
は4096
に設定した。
- データを埋め込む
- 検証テストをする
検証テスト結果(nomic-embed-text)
- 「母子手帳」で検索 →ダメ
- 「児童手当」で検索 →ダメ
- 「保育園に入れたい」で検索 →ギリギリ合格
- 「金属ごみの出し方を知りたい」で検索 →ダメ
- 「粗大ごみの出し方」で検索 →ダメ
→**nomic-embed-text
もダメ**
検証テスト結果(snowflake-arctic-embed)
- 「母子手帳」で検索 →ダメ
- 「児童手当」で検索 →ダメ
- 「保育園に入れたい」で検索 →ダメ
- 「金属ごみの出し方を知りたい」で検索 →ダメ
- 「粗大ごみの出し方」で検索 →ギリギリ合格
→**snowflake-arctic-embed
もダメ**

Difyと一緒にOllamaもDockerで動かしてみる
ゴール
- Difyのdocker-compose.yamlにOllamaも追記して、Docker上でOllamaを稼働させる
※現状はwindowsアプリとして起動させている
まとめ
- 問題なく動いたが、現状CPUしか使えていない
- ⇒GPUで動くようにするのはまた今度
関連リンク
- 参考ブログ:「DifyとOllamaでオープンなRAG型チャットボットを構築してみた。」
※参考にさせていただきました。 - Docker Hub Ollama導入手順
※GPUを使う場合の手順はここに書いてある。
手順
コンテナの再構築
- dify/dockerフォルダでPowerShellを起動して、Difyを停止する。
docker-compose down
※Docker Desktopの停止ボタンを押しても良い。
2. docker-compose.yamlを次のように書き替える
修正したdocker-compose.yaml
version: '3'
services:
api:
image: langgenius/dify-api:0.6.10
restart: always
environment:
MODE: api
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
CONSOLE_WEB_URL: 'http://(DifyをホストするPCの静的IPを記載):8080' #追加
INIT_PASSWORD: ''
CONSOLE_API_URL: 'http://(DifyをホストするPCの静的IPを記載):8080' #追加
SERVICE_API_URL: 'http://(DifyをホストするPCの静的IPを記載):8080' #追加
APP_WEB_URL: 'http://(DifyをホストするPCの静的IPを記載):8080' #追加
FILES_URL: 'http://(DifyをホストするPCの静的IPを記載):8080' #追加
FILES_ACCESS_TIMEOUT: 300
MIGRATION_ENABLED: 'true'
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_USE_SSL: 'false'
REDIS_DB: 0
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
WEB_API_CORS_ALLOW_ORIGINS: '*'
CONSOLE_CORS_ALLOW_ORIGINS: '*'
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3_SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
SENTRY_DSN: ''
SENTRY_TRACES_SAMPLE_RATE: 1.0
SENTRY_PROFILES_SAMPLE_RATE: 1.0
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
CODE_EXECUTION_ENDPOINT: "http://sandbox:8194"
CODE_EXECUTION_API_KEY: dify-sandbox
CODE_MAX_NUMBER: 9223372036854775807
CODE_MIN_NUMBER: -9223372036854775808
CODE_MAX_STRING_LENGTH: 80000
TEMPLATE_TRANSFORM_MAX_LENGTH: 80000
CODE_MAX_STRING_ARRAY_LENGTH: 30
CODE_MAX_OBJECT_ARRAY_LENGTH: 30
CODE_MAX_NUMBER_ARRAY_LENGTH: 1000
SSRF_PROXY_HTTP_URL: 'http://ssrf_proxy:3128'
SSRF_PROXY_HTTPS_URL: 'http://ssrf_proxy:3128'
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
worker:
image: langgenius/dify-api:0.6.10
restart: always
environment:
CONSOLE_WEB_URL: ''
MODE: worker
LOG_LEVEL: INFO
SECRET_KEY: sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U
DB_USERNAME: postgres
DB_PASSWORD: difyai123456
DB_HOST: db
DB_PORT: 5432
DB_DATABASE: dify
REDIS_HOST: redis
REDIS_PORT: 6379
REDIS_USERNAME: ''
REDIS_PASSWORD: difyai123456
REDIS_DB: 0
REDIS_USE_SSL: 'false'
CELERY_BROKER_URL: redis://:difyai123456@redis:6379/1
STORAGE_TYPE: local
STORAGE_LOCAL_PATH: storage
S3_ENDPOINT: 'https://xxx.r2.cloudflarestorage.com'
S3_BUCKET_NAME: 'difyai'
S3_ACCESS_KEY: 'ak-difyai'
S3_SECRET_KEY: 'sk-difyai'
S3_REGION: 'us-east-1'
AZURE_BLOB_ACCOUNT_NAME: 'difyai'
AZURE_BLOB_ACCOUNT_KEY: 'difyai'
AZURE_BLOB_CONTAINER_NAME: 'difyai-container'
AZURE_BLOB_ACCOUNT_URL: 'https://<your_account_name>.blob.core.windows.net'
GOOGLE_STORAGE_BUCKET_NAME: 'yout-bucket-name'
GOOGLE_STORAGE_SERVICE_ACCOUNT_JSON_BASE64: 'your-google-service-account-json-base64-string'
VECTOR_STORE: weaviate
WEAVIATE_ENDPOINT: http://weaviate:8080
WEAVIATE_API_KEY: WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih
QDRANT_URL: http://qdrant:6333
QDRANT_API_KEY: difyai123456
QDRANT_CLIENT_TIMEOUT: 20
QDRANT_GRPC_ENABLED: 'false'
QDRANT_GRPC_PORT: 6334
MILVUS_HOST: 127.0.0.1
MILVUS_PORT: 19530
MILVUS_USER: root
MILVUS_PASSWORD: Milvus
MILVUS_SECURE: 'false'
MAIL_TYPE: ''
MAIL_DEFAULT_SEND_FROM: 'YOUR EMAIL FROM (eg: no-reply <no-reply@dify.ai>)'
SMTP_SERVER: ''
SMTP_PORT: 465
SMTP_USERNAME: ''
SMTP_PASSWORD: ''
SMTP_USE_TLS: 'true'
SMTP_OPPORTUNISTIC_TLS: 'false'
RESEND_API_KEY: ''
RESEND_API_URL: https://api.resend.com
RELYT_HOST: db
RELYT_PORT: 5432
RELYT_USER: postgres
RELYT_PASSWORD: difyai123456
RELYT_DATABASE: postgres
PGVECTOR_HOST: pgvector
PGVECTOR_PORT: 5432
PGVECTOR_USER: postgres
PGVECTOR_PASSWORD: difyai123456
PGVECTOR_DATABASE: dify
NOTION_INTEGRATION_TYPE: public
NOTION_CLIENT_SECRET: you-client-secret
NOTION_CLIENT_ID: you-client-id
NOTION_INTERNAL_SECRET: you-internal-secret
INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH: 1000
depends_on:
- db
- redis
volumes:
- ./volumes/app/storage:/app/api/storage
networks:
- ssrf_proxy_network
- default
web:
image: langgenius/dify-web:0.6.10
restart: always
environment:
CONSOLE_API_URL: ''
APP_API_URL: ''
SENTRY_DSN: ''
networks: #追加
- ssrf_proxy_network #追加
- default #追加
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: postgres
POSTGRES_PASSWORD: difyai123456
POSTGRES_DB: dify
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
#- ./volumes/db/data:/var/lib/postgresql/data
- postgres_data:/var/lib/postgresql/data #変更
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
networks: #追加
- default #追加
redis:
image: redis:6-alpine
restart: always
volumes:
- ./volumes/redis/data:/data
command: redis-server --requirepass difyai123456
healthcheck:
test: [ "CMD", "redis-cli", "ping" ]
networks: #追加
- default #追加
weaviate:
image: semitechnologies/weaviate:1.19.0
restart: always
volumes:
- ./volumes/weaviate:/var/lib/weaviate
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: 'false'
PERSISTENCE_DATA_PATH: '/var/lib/weaviate'
DEFAULT_VECTORIZER_MODULE: 'none'
CLUSTER_HOSTNAME: 'node1'
AUTHENTICATION_APIKEY_ENABLED: 'true'
AUTHENTICATION_APIKEY_ALLOWED_KEYS: 'WVF5YThaHlkYwhGUSmCRgsX3tD5ngdN8pkih'
AUTHENTICATION_APIKEY_USERS: 'hello@dify.ai'
AUTHORIZATION_ADMINLIST_ENABLED: 'true'
AUTHORIZATION_ADMINLIST_USERS: 'hello@dify.ai'
networks: #追加
- default #追加
sandbox:
image: langgenius/dify-sandbox:0.2.1
restart: always
environment:
API_KEY: dify-sandbox
GIN_MODE: 'release'
WORKER_TIMEOUT: 15
ENABLE_NETWORK: 'true'
HTTP_PROXY: 'http://ssrf_proxy:3128'
HTTPS_PROXY: 'http://ssrf_proxy:3128'
SANDBOX_PORT: 8194
volumes:
- ./volumes/sandbox/dependencies:/dependencies
networks:
- ssrf_proxy_network
ssrf_proxy:
image: ubuntu/squid:latest
restart: always
volumes:
- ./volumes/ssrf_proxy/squid.conf:/etc/squid/squid.conf
networks:
- ssrf_proxy_network
- default
nginx:
image: nginx:latest
restart: always
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf
- ./nginx/proxy.conf:/etc/nginx/proxy.conf
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- api
- web
ports:
- "8080:80" #80:80から変更
networks: #追加
- default #追加
# ----------------------------------------
# 240609: Ollamaを追加
# ----------------------------------------
ollama: #追加
image: ollama/ollama
restart: always
container_name: ollama
ports:
- "11434:11434"
volumes:
- ollama:/root/.ollama
networks:
ssrf_proxy_network:
driver: bridge
internal: true
default: #追加
driver: bridge
volumes: #追加
postgres_data: #追加
ollama: #追加
コンテナの関係を可視化
- Difyを再起動
# ollamaイメージをダウンロード
docker-compose pull ollama
# difyを再起動。
docker-compose up -d
OllamaにLlama3導入
- Docker上のollamaにllama3を導入
ollamaコンテナに入る
docker exec -it ollama /bin/sh
ollamaコンテナでコマンドを実行
ollama pull llama3
Docker Desktopから簡単にアクセスできる
- Chrome拡張機能のollama-uiでLlama3が稼働していることを確認する
確認方法
- ollama-uiを導入
- 問題なければ
llama3
モデルが選択できる
- チャットもできた
DifyとOllama(Llama3)を連携
- Diryにアクセス
- 画面右上のアカウントをクリック⇒
モデルプロバイダー
⇒Ollama
⇒Add Model
⇒下図のように設定
Difyで動作検証
- 既存チャットボットのモデルをOllmaのLlama3に切り替えて動かしてみた(割愛)
- やはりCPUしか使っていないのでレスポンスが遅い。。
タスクマネージャーの画面

DifyアプリにAPIアクセスする
ゴール
- Dify APIエンドポイントにAPIリクエストを送信する
まとめ
- Chrome拡張機能のTalend API TesterからのPOSTリクエストが成功した
関連リンク
- Dify公式doc API利用方法
- Chrome拡張機能 Talend API Tester - Free Edition
手順
DifyチャットアプリのAPIキーを取得する
- Difyでチャットアプリを作る
- 概要からAPIキーを取得する
- Chromeブラウザに
Talend API Tester
拡張機能を導入する - Dify公式docなどを参考に、下図のように設定する
参考にしたもの
Dify公式doc
import requests
import json
url = 'https://api.dify.ai/v1/chat-messages'
headers = {
'Authorization': 'Bearer ENTER-YOUR-SECRET-KEY',
'Content-Type': 'application/json',
}
data = {
"inputs": {},
"query": "eh",
"response_mode": "streaming",
"conversation_id": "1c7e55fb-1ba2-4e10-81b5-30addcea2276",
"user": "abc-123"
}
response = requests.post(url, headers=headers, data=json.dumps(data))
print(response.json())
アプリのAPIアクセスページ
curl -X POST 'http://161.93.110.41:8080/v1/chat-messages' \
--header 'Authorization: Bearer {api_key}' \
--header 'Content-Type: application/json' \
--data-raw '{
"inputs": {},
"query": "What are the specs of the iPhone 13 Pro Max?",
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
}'
BODYは次のとおり
※会話IDは空欄
※テキストチャットなら"files"は不要
{
"query": "こんにちは",
"response_mode": "streaming",
"conversation_id": "",
"user": "abc-123",
"inputs": {},
"files": [
{
"type": "image",
"transfer_method": "remote_url",
"url": "https://cloud.dify.ai/logo/logo-site.png"
}
]
}
- SENDを押す⇒成功!

Dify+OllamaでRAGチャットボットを作る#2
ゴール
- ローカルだけで完結するRAG検索チャットボットを作る
まとめ
- ollama pullできる多言語対応埋め込みモデルがあったので作れたが、精度は悪く、実用には堪えない。
関連リンク
- Ollama pullできる多言語対応埋め込みモデル
手順
- Ollamaトップページの検索窓で
embedding multi
みたいなキーワードを入力して検索する - ヒットしたモデルのなかで、多言語対応の埋め込みモデルの
paraphrase-multilingual-minilm
と日本語LLMのFugaku-llm
をollama pullする
ollama pull nextfire/paraphrase-multilingual-minilm
ollama run nebel/fugaku-llm:13b-instruct
- ollamaを起動する
- Difyに2つのモデルを登録する
Dify登録画面
paraphrase-multilingual-minilmを登録
Fugaku-llmの登録
- Difyでまずナレッジを埋め込む
- 元データはLINEの公開している子育てAIチャットボット用のサンプルFAQデータセットを使う
- チャンク設定は
自動
、インデックスモードは高品質
、top-Kは8
- 埋め込みが完了したら、検索テストをしてみる
頑張ってはいるが精度はいまいち。。
検索テストの結果
- RAGアプリを作る
下図のようにつくった
アプリ作成画面
アプリ全体のアーキテクチャ
Fugaku-llmの詳細設定
- デバッグとプレビュー機能を使って検索してみる
検索結果
→うーむ、使えたものじゃない。。

Difyを0.6.10から0.6.12fix1にアップデートする
ゴール
- Dify0.6.12fix1にバージョンアップする
- 0.6.10環境のデータを引き継ぐ
まとめ
- 0.6.12fix1は起動できたが、0.6.10環境のデータの引継ぎはできず。。
- これまでのようにdocker-compose.yamlの内容をあれこれ触らなくても起動した。
- ただしPostgresDBのデータ保管場所だけは従来と同じく変えた(後述)
関連リンク
- Difyリリースノート ※更新方法もある
手順
(背景)
- 別のPCのDify0.6.10環境にDify0.6.12fixを上書きするインストールしたが、データ継承されなかった。
- このPCのDify0.6.10環境は絶対壊したくないので、既存のDify0.6.10環境を残して、新たにDify0.6.12fix1環境を作った。以下はその手順。
PowerShellで実行するコマンド
# difyフォルダをコピー
cp dify dify_latest
# コピー先のdockerディレクトリに移動
cd dify_latest\docker\
# 手元のフォルダのタグを確認
git tag
# ⇒0.6.10までだった
# リモートのタグ情報を取得
git fetch --tags
# 再度タグを確認
git tag
# ⇒0.6.12fix1までになった
# mainブランチに切り替え
git checkout main
# リモートのmainブランチの最新内容を取得(=fetch+merge)
git pull origin main
# ⇒手元のdocker-compose.yamlをコミットしていないのでダメとエラーが出た
# docker-compose.yamlの変更を破棄
git checkout -- docker-compose.yaml
# ⇒docker-compose.yamlが上書きされるので、
# docker-compose_0.6.10stable.yamlという名前にして、別のフォルダに保存する
# 改めてmainブランチの最新内容を取得
git pull origin main
# →今度はできた
# 手動でdocker-compose.yamlの中身を書き換える(後述)
# .env.sampleファイルを.envという名前に変えて、中身を書き換える(後述)
# コンテナをdify0_6_12という名前で起動
docker-compose -p dify0_6_12 up -d
# ⇒無事起動!
-
GitHubリポジトリにあるファイルへのリンク:
-
docker-compose.yamlと.envファイルの変更点:
db:
volumes:
# 変更後
- postgres_data:/var/lib/postgresql/data #追加
# 変更前
# - ./volumes/db/data:/var/lib/postgresql/data
volumes:
oradata:
postgres_data: #追加
# ------------------------------
# Common Variables
# ------------------------------
# ホストマシンのIPに変更
CONSOLE_API_URL=http://161.93.***.**:8880 #追加
CONSOLE_WEB_URL=http://161.93.***.**:8880 #追加
SERVICE_API_URL=http://161.93.***.**:8880 #追加
APP_API_URL=http://161.93.***.**:8880 #追加
APP_WEB_URL=http://161.93.***.**:8880 #追加
FILES_URL=http://161.93.***.**:8880 #追加
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=8880 #80から変更
EXPOSE_NGINX_SSL_PORT=8443 #443から変更

Firecrawlをセルフホストして、Difyで使う
ゴール
- Firecrawlをセルフホストして、Difyと連携する
- Firecrawlはサイトをクロールしてマークダウンに変換するツール
- FirecrawlをDifyと連携させると、サイトデータをナレッジとして簡単に埋め込めるようになる
まとめ
- Firecrawlをセルフホストできた
- Difyと連携して、外部サイトデータ(githubリポジトリ)をナレッジにできた
- しかし、社内サイト(SharePointOnlineサイト、OneDriveなど)はできなかった
関連リンク
手順
- FirecrawlをDockerから起動するまで
-
公式サイトとこちらのZenn記事を参考にすすめた。
-
difyフォルダのあるフォルダでPowerShellを立ち上げて、以下を実行する。
# リポジトリをクローン
git clone https://github.com/mendableai/firecrawl.git
# ディレクトリに移動
cd firecrawl
# 深い階層にある.env.sampleを現在のディレクトリに.envとしてコピー
cp ./apps/api/.env.example .env
# .envの中身を書き換える(後述)
# dockerコンテナを立てる
docker-compose build
#⇒かなり時間かかるが、待てば処理が終わる。
docker-compose up -d
#⇒かなり時間かかるが、無事起動!
- GitHubリポジトリへのリンク
- docker-compose.yaml ※このまま使う
- .env.sample ※名前を.envに変えてから、下記のように修正
.env
# ===== Required ENVS ======
NUM_WORKERS_PER_QUEUE=8
PORT=3002
HOST=0.0.0.0
# 変更前
# REDIS_URL=redis://localhost:6379
# 変更後
REDIS_URL=redis://redis:6379
PLAYWRIGHT_MICROSERVICE_URL=http://playwright-service:3000/html
## To turn on DB authentication, you need to set up supabase.
# trueから変更
USE_DB_AUTHENTICATION=false
# ===== Optional ENVS ======
# Supabase Setup (used to support DB authentication, advanced logging, etc.)
# 変更後
SUPABASE_ANON_TOKEN=dummy_token
SUPABASE_URL=http://dummy_url
SUPABASE_SERVICE_TOKEN=dummy_service_token
# Other Optionals
# 変更前
# TEST_API_KEY= # use if you've set up authentication and want to test with a real API key
# 変更後
TEST_API_KEY=fc-test
RATE_LIMIT_TEST_API_KEY_SCRAPE= # set if you'd like to test the scraping rate limit
RATE_LIMIT_TEST_API_KEY_CRAWL= # set if you'd like to test the crawling rate limit
SCRAPING_BEE_API_KEY= #Set if you'd like to use scraping Be to handle JS blocking
OPENAI_API_KEY= # add for LLM dependednt features (image alt generation, etc.)
BULL_AUTH_KEY= @
LOGTAIL_KEY= # Use if you're configuring basic logging with logtail
LLAMAPARSE_API_KEY= #Set if you have a llamaparse key you'd like to use to parse pdfs
SERPER_API_KEY= #Set if you have a serper key you'd like to use as a search api
SLACK_WEBHOOK_URL= # set if you'd like to send slack server health status messages
POSTHOG_API_KEY= # set if you'd like to send posthog events like job logs
POSTHOG_HOST= # set if you'd like to send posthog events like job logs
STRIPE_PRICE_ID_STANDARD=
STRIPE_PRICE_ID_SCALE=
STRIPE_PRICE_ID_STARTER=
STRIPE_PRICE_ID_HOBBY=
STRIPE_PRICE_ID_HOBBY_YEARLY=
STRIPE_PRICE_ID_STANDARD_NEW=
STRIPE_PRICE_ID_STANDARD_NEW_YEARLY=
STRIPE_PRICE_ID_GROWTH=
STRIPE_PRICE_ID_GROWTH_YEARLY=
HYPERDX_API_KEY=
HDX_NODE_BETA_MODE=1
FIRE_ENGINE_BETA_URL= # set if you'd like to use the fire engine closed beta
# Proxy Settings for Playwright (Alternative you can can use a proxy service like oxylabs, which rotates IPs for you on every request)
PROXY_SERVER=
PROXY_USERNAME=
PROXY_PASSWORD=
# set if you'd like to block media requests to save proxy bandwidth
BLOCK_MEDIA=
# Set this to the URL of your webhook when using the self-hosted version of FireCrawl
SELF_HOSTED_WEBHOOK_URL=
# Resend API Key for transactional emails
RESEND_API_KEY=
- ブラウザから起動を確認する
-
http://localhost:3002/
⇒SCRAPERS-JS: Hello, world! Fly.io
と表示される -
http://host.docker.internal:3002/
⇒SCRAPERS-JS: Hello, world! Fly.io
と表示される -
http://localhost:3002/test
⇒Hello, world!
が表示される -
http://host.docker.internal:3002/test
⇒Hello, world!
が表示される
-
- Difyと連携する
- 設定項目
- API Key:
fc-test
- Base URL:
http://host.docker.internal:3002
- API Key:
画面キャプチャ
- Difyトップ画面 ⇒ナレッジ ⇒ウェブサイトから同期 ⇒設定:データベース ⇒ FireCrawlのConfigureを選択
- 以下のように設定
- 成功!
- ウェブサイトをナレッジにしてみる
- GitHubリポジトリはできた
- 社内サイト(SharePointOnlineサイト、OneNoteなど)はクロールできず。。
画面キャプチャ
- Difyリポジトリをナレッジにしてみる
※以下割愛

Langfuseをセルフホストして、Difyで使う #1
ゴール
- Langfuseをセルフホストする
- LangfuseとDifyを連携して、DifyアプリをLangfuseでトレースする
まとめ
- セルフホストは簡単にできた(http://localhost:3000)
- ただしDifyはhttps通信でないと連携できない!⇒ 次回に続く
関連リンク
手順
- Langfuseを起動する
# Langfuseリポジトリをcloneする
git clone https://github.com/langfuse/langfuse.git
# langufuseフォルダに移動
cd langfuse
# docker-compose.yamlをすこし書き換える(後述)
# langfuseを起動
docker-compose up -d
# ⇒特に問題なく起動!
docker-compose.yml
- オリジナルの docker-compose.yml
- 修正後(変更箇所は1か所だけ)
services:
langfuse-server:
image: langfuse/langfuse:2
depends_on:
db:
condition: service_healthy
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://postgres:postgres@db:5432/postgres
- NEXTAUTH_SECRET=mysecret
- SALT=mysalt
# 変更前
# - NEXTAUTH_URL=http://localhost:3000
# 変更後(ホストするPCのIPアドレスに書き換える)
- NEXTAUTH_URL=http://161.93.***.**:3000
- TELEMETRY_ENABLED=${TELEMETRY_ENABLED:-true}
- LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES=${LANGFUSE_ENABLE_EXPERIMENTAL_FEATURES:-false}
db:
image: postgres
restart: always
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 3s
timeout: 3s
retries: 10
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=postgres
ports:
- 5432:5432
volumes:
- database_data:/var/lib/postgresql/data
volumes:
database_data:
driver: local
- Langfuseにサインアップする
画面キャプチャ
- ブラウザで
localhost:3000
にアクセスすると、サインイン画面になる。
- まずはサインアップする
- あらためてサインインすると、初期画面になった。
- Difyと連携する
- セルフホストしているhttpサーバを指定するとエラーになる。。(今回はここまで)

API経由でナレッジを操作する
ゴール
- APIを使ってナレッジを操作できるようになる。
まとめ
- 簡単にできた。これを使えば、ファイルの更新や追加があるたびに埋め込み処理を実行したり、自作のwebアプリ経由でナレッジを追加したりできる。
- ただし、ナレッジ削除も簡単にできてしまうので注意が必要。
参考リンク
- Dify公式doc APIによるデータセットの維持
手順
- 公式docはcURLコマンドのサンプルがあるので、これをPythonコードに書き換えて実行してみる。
- いずれも問題なく実行できた。
ナレッジ一覧(ナレッジ名とデータセットID)の取得
データセットIDはdataset_idとして後続コードでも利用します。
import requests
import json
# -------------------------------
# ユーザー設定
api_key = "dataset-**********" # APIキー
endpoint = "http://161.93.***:**:8880/v1/datasets?page=1&limit=500" # エンドポイント
# -------------------------------
headers = {"Authorization": f"Bearer {api_key}"}
# GETリクエストを送信
response = requests.get(endpoint, headers=headers)
response = response.json() # JSON形式に変換
# dataから、ナレッジのnameとidだけを取得して表示
for knowledge in response["data"]:
print("="*100)
print(f"ナレッジ名: {knowledge['name']}")
print(f"データセットID: {knowledge['id']}")
新規ナレッジの作成
import requests
import json
# -------------------------------
# ユーザー設定
api_key = "dataset-**********"
endpoint = "http://161.93.***:**:8880/v1/datasets"
new_knowledge_name = "API-Knowledge 5" # 新しいナレッジの名前
# -------------------------------
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
payload = {"name": new_knowledge_name}
# POSTリクエストを送信して新しいナレッジを作成
response = requests.post(endpoint, headers=headers, data=json.dumps(payload))
response = response.json()
# dataにstatusコードが含まれていないときだけ実行する
if "status" not in response:
# dataから、ナレッジのnameとidだけを取得して表示
print("="*100)
print(f"Name: {response['name']}")
print(f"ID: {response['id']}")
else:
# data全体を見やすく表示
print(json.dumps(response, indent=4))
既存ナレッジの削除
import requests
import json
# -------------------------------
# ユーザー設定
api_key = "dataset-**********" # APIキー
dataset_id = "******************" # 削除するナレッジのID
# -------------------------------
endpoint = f"http://161.93.***:**:8880/v1/datasets/{dataset_id}"
headers = {"Authorization": f"Bearer {api_key}"}
# DELETEリクエストを送信してナレッジを削除
response = requests.delete(endpoint, headers=headers)
# レスポンスを表示
if response.status_code == 204:
print("Knowledge deleted successfully.")
else:
print(f"Failed to delete knowledge. Status code: {response.status_code}")
ファイルからドキュメントを作成
import requests
import json
# -------------------------------
# ユーザー設定
api_key = "dataset-**********" # APIキー
dataset_id = "******************" # ドキュメントを追加するナレッジのID
file_path = r"ファイルパス" # ドキュメントとして追加するファイルのパス
# -------------------------------
endpoint = f"http://161.93.***:**:8880/v1/datasets/{dataset_id}/document/create_by_file"
headers = {"Authorization": f"Bearer {api_key}"}
# 処理方法
# 自動埋め込みならこれだけ
process_rule = {"mode": "automatic"}
# カスタム埋め込みならこちらを使う
# process_rule = {
# "mode": "custom"
# "rules": {
# "pre_processing_rules": [
# {"id": "remove_extra_spaces", "enabled": True}, # 余分なスペースを削除
# {"id": "remove_urls_emails", "enabled": False} # URLとメールアドレスを削除
# ],
# "segmentation": {"separator": "###", "max_tokens": 1000} # セグメントの設定
# }
# }
data = {
"indexing_technique": "high_quality", # インデックス技術
"process_rule": process_rule # プロセスルール
}
files = {
'file': open(file_path, 'rb'),
'data': (None, json.dumps(data), 'application/json')
}
# POSTリクエストを送信して新しいドキュメントを作成
response = requests.post(endpoint, headers=headers, files=files)
response = response.json()
# 結果を見やすく表示
print(json.dumps(response, indent=4))
テキストからドキュメントを作成
import requests
import json
# -------------------------------
# ユーザー設定
api_key = "dataset-**********"
dataset_id = "******************" # ドキュメントを追加するナレッジのID
document_name = "Sample Document"
document_text = """生成AIの業務利用には以下の点に注意が必要です。
まず、生成AIが提供する情報の正確性や信頼性を常に確認してください。
生成AIは誤った情報を生成する可能性があるため、重要な決定に使用する前に専門家によるレビューが必要です。
次に、データのプライバシーとセキュリティを確保するため、適切なアクセス制御とデータ保護対策を講じてください。
また、生成AIの利用が法令や規制に準拠していることを確認することも重要です。
最後に、生成AIが生成するコンテンツの著作権や倫理的側面についても注意し、適切な利用範囲を守るようにしてください。
これらのポイントを遵守することで、生成AIの業務利用が効果的かつ安全になります。
"""
# -------------------------------
# APIエンドポイントURL
endpoint = f"http://161.93.***:**:8880/v1/datasets/{dataset_id}/document/create_by_text"
headers = {
"Authorization": f"Bearer {api_key}",
"Content-Type": "application/json"
}
# POSTデータを作成
payload = {
"name": document_name,
"text": document_text,
"indexing_technique": "high_quality",
"process_rule": {"mode": "automatic"}
}
# POSTリクエストを送信して新しいドキュメントを作成
response = requests.post(endpoint, headers=headers, data=json.dumps(payload))
response = response.json()
# 結果を見やすく表示
print(json.dumps(response, indent=4))
ナレッジのドキュメント一覧を取得
import requests
import json
# APIキーとdataset_idを設定
api_key = "dataset-ydCFZztP4M**************"
dataset_id = "9d93bf86-0354-4211-af2**********"
headers = {"Authorization": f"Bearer {api_key}"}
url_get_documents = f"http://161.93.+++.+++:8880/v1/datasets/{dataset_id}/documents"
response_get_documents = requests.get(url_get_documents, headers=headers)
if response_get_documents.status_code == 200:
documents = response_get_documents.json()
# print("Documents:", documents) # そのまま出力
# print(json.dumps(documents, indent=4)) # 見やすく表示
# "id"と"name"だけ出力
print("Document ID and Name")
for d in documents["data"]:
print(d["id"], d["name"])
else:
print(f"Failed to retrieve documents. Status code: {response_get_documents.status_code}")
ナレッジのドキュメントを削除
import requests
api_key = "dataset-ydCFZztP4MSgwa**********"
dataset_id = "9d93bf86-0354-4211-af20-89**********"
document_id = "****************" # 削除するドキュメントのID
url_delete_document = f"http://161.93.+++.+++:8880/v1/datasets/{dataset_id}/documents/{document_id}"
headers = {"Authorization": f"Bearer {api_key}"}
response_delete_document = requests.delete(url_delete_document, headers=headers)
if response_delete_document.status_code == 204:
print("Document deleted successfully.")
else:
print(f"Failed to delete document. Status code: {response_delete_document.status_code}")

Dify0.6.12fix1から0.6.14にアップデートする
ゴール
- Dify0.6.14にアップデートする
- Dify0.6.12fix1のデータを引き継ぐ
まとめ
- スムーズにアップデートできた。データ引き継ぎも問題なし。
関連リンク
- [Dify0.6.14リリースノート] (https://github.com/langgenius/dify/releases/tag/0.6.14) ※更新方法もある
手順
PowerShellで実行するコマンド
# difyのdockerフォルダに移動して
docker-compose down
# ダウンロード済みのタグを確認
git tag
# ⇒0.6.13までだった
# リモートのタグ情報を取得
git fetch --tags
# 再度タグ確認
git tag
# ⇒0.6.14までになった
# mainブランチに切り替え
git checkout main
# リモートのmainブランチの最新内容をpull(=fetch+merge)
# ※git checkput main しているので git pull でもよい
git pull origin main
# ⇒手元のdocker-compose.yamlなどの更新がコミットされていないというエラーが出る
# ⇒docker-compose.yamlと.envファイルだけ「バックアップ」フォルダを作ってコピーしておく
# スタッシュする
git stash
# あらためてpull
# ※これもgit pullでよい
git pull origin main
# docker-compose.yamlと.envファイルを書き替える(後述)
# コンテナを起動
docker-compose up -d
# ※docker-compose -p dify0_6_14 up -dのようにコンテナ名を変えるとデータ継承されない
# ⇒無事起動!データも継承されている。
- docker-compose.yamlと.envファイルの変更点:
###############
# 変更1箇所目
###############
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: ${PGUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
volumes:
# - ./volumes/db/data:/var/lib/postgresql/data #オリジナル
- postgres_data:/var/lib/postgresql/data #追加
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
ports: #追加(SQLツールからアクセスできるように)
- "5432:5432" #追加
###############
# 変更2箇所目
###############
volumes:
oradata:
postgres_data: #追加
# ホストマシンのIPに変更
# ------------------------------
# Common Variables
# ------------------------------
CONSOLE_API_URL=http://161.93.+++.+++:8080
CONSOLE_WEB_URL=http://161.93.+++.+++:8080
SERVICE_API_URL=http://161.93.+++.+++:8080
APP_API_URL=http://161.93.+++.+++:8080
APP_WEB_URL=http://161.93.+++.+++:8080
FILES_URL=http://161.93.+++.+++:8080
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=8080 #80から変更
EXPOSE_NGINX_SSL_PORT=8443 #443から変更

DifyコンテナのPostgresデータベースにSQLツールから接続する
ゴール
- DifyのPostgresデータベースにSQLツールのA5:SQL Mk2から接続する
まとめ
- 簡単にできた。
- DBに格納されているデータに簡単にアクセスできるようになった。
参考リンク
Difyが動かしている3つのデータベースについて
Postgresデータベースには、Difyアプリケーションに関連する多くの永続的なデータが格納されます。
具体的には以下のような情報が含まれます。
- ユーザーデータ: ユーザーアカウント、プロフィール情報、認証情報など。
- アプリケーションデータ: アプリケーション設定、構成情報、使用状況ログなど。
- メッセージデータ: チャットや会話のログ、メッセージの履歴など。
- APIトークン: 外部サービスとの連携に使用されるAPIトークン。
- アノテーションデータ: アノテーションに関連する設定や履歴。
- ワークフローデータ: ワークフローの定義や実行履歴。
Redisはインメモリデータベースで、高速アクセスが必要なデータのキャッシュやセッション情報の格納に使用されます。具体的には以下のような情報が含まれます。
- セッションデータ: ユーザーのセッション情報、ログイン状態など。
- キャッシュデータ: 頻繁にアクセスされるデータのキャッシュ(例: ユーザー設定やアプリケーション設定)。
- キュー: ジョブキューやタスクキュー(Celeryなどのバックエンドタスク処理で使用)。
Weaviateはベクトル検索エンジンで、ベクトルデータや意味的検索に関連する情報を格納します。具体的には以下のような情報が含まれます。
- ベクトルデータ: テキストやその他のデータのベクトル表現。
- メタデータ: 各ベクトルに関連するメタデータ(例: ドキュメントIDやその他の関連情報)。
- 検索インデックス: 効率的なベクトル検索をサポートするためのインデックス。
手順
- docker-compose.yamlに外部ポート開放設定を追加
# The postgres database.
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: ${PGUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
volumes:
# 変更後
# 名前付きボリューム postgres_data をコンテナ内のディレクトリ /var/lib/postgresql/data にマウントします。
- postgres_data:/var/lib/postgresql/data #追加
# オリジナルは下記
# ./volumes/db/data をコンテナ内のディレクトリ /var/lib/postgresql/data にマウントします。
# - ./volumes/db/data:/var/lib/postgresql/data
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
ports: #追加
- "5433:5432" #追加 5432でなく5433を使います!
- コンテナを
docker-compose up -d
などで起動。 - A5:SQL Mk2を起動して、以下のように設定する。
.env設定を変えていないならば、
- データベース名:
dify
- ユーザーID:
postgres
- パスワード:
difyai123456
⇒設定が正しいかは、「テスト接続」ですぐ確認できる。
- 接続すると、
public
スキーマにあるテーブルに各種データが格納されていることがわかる。
-
accounts
テーブル- Difyアカウント情報(id、登録名、メールアドレス、登録日など)
-
apps
テーブル- アプリ情報(アプリid、アプリ名、テナントid、作成日など)
-
datasets
テーブル- ナレッジのデータセット情報(id、ファイル名、埋め込み方法など)
-
documents
テーブル- ナレッジに格納しているドキュメント情報
-
end_users
テーブル- Difyアプリを使ったユーザー情報(利用したアプリid、登録日など)
-
messages
テーブル- チャット履歴(id、アプリid、会話id、クエリ、トークン数、ユーザーid(from_end_user_id、from_account_idのいずれか)、作成日など)

ベクトルデータベースとの接続トラブル対処記録
ゴール
- ベクトルデータベース(weaviate)とDify本体(sandbox)が通信できない不具合を解消する。
まとめ
- middlewareコンテナを停止、再起動したら解消した。
- ⇒ middlewareの何が悪かったのかは未解明。
手順
- 前日まで問題なく動いていたが、朝から次の症状が出た
- ナレッジの埋め込みはできるが、データベースに登録できない
- RAGアプリでナレッジ検索ブロックでデータベースに接続できない
- 確認したこと
- ログ ⇒問題ない
- ストレージ ⇒十分余裕がある
- ファイル ⇒壊れていない
- Dify本体コンテナの停止、再起動 ⇒症状改善しない
- Dify本体をバージョンアップ(0.6.14⇒0.6.15)⇒症状改善しない
- Dify-middlewareを停止、再起動 ⇒ 症状改善した

Dify0.6.15から0.7.0にアップデートする
ゴール
- Dify0.7.0にアップデートする
まとめ
- スムーズにアップデートできた。データ引き継ぎも問題なし。
- middlewareは変化なしだったのでそのまま稼働中。
関連リンク
- Dify0.7.0リリースノート ※更新方法もある
手順
- gitから最新版をpullするまでは 0.6.15へのアップデートと同じ
# difyのdockerフォルダに移動して、起動中の環境を落とす
docker-compose down
# いまのdocker-compose.yamlとか.envファイルを別フォルダにコピー(バックアップ)する
# データバックアップはしない
# 最新バージョンをpullするために、現在のフォルダ状態をスタッシュ
git stash
# mainブランチに切り替え
git checkout main
# リモートのタグ情報を取得
git fetch --tags
# タグ確認
git tag
# ⇒0.7.0まであることを確認
# 最新バージョンをpull
git pull origin main
# docker-compose.yamlと.envファイルを書き換える(後述)
# コンテナを起動
docker-compose up -d
- docker-compose.yamlと.envファイルの変更点:
### 変更1箇所目 #################################
# The postgres database.
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: ${PGUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
-c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
volumes:
# - ./volumes/db/data:/var/lib/postgresql/data #オリジナル
- postgres_data:/var/lib/postgresql/data #追加
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
### 変更2箇所目 #################################
volumes:
oradata:
dify_es01_data:
postgres_data: #追加
# ホストマシンのIPに変更
# ------------------------------
# Common Variables
# ------------------------------
CONSOLE_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
CONSOLE_WEB_URL=http://161.93.+++.++:8880 #オリジナルは空欄
SERVICE_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
APP_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
APP_WEB_URL=http://161.93.+++.++:8880 #オリジナルは空欄
FILES_URL=http://161.93.+++.++:8880 #オリジナルは空欄
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=8880 #オリジナルは80
EXPOSE_NGINX_SSL_PORT=8443 #オリジナルは443

Firecrawlをセルフホストして、Difyで使う #2
ゴール
- Dify0.7.0にバージョンアップしたら動かなくなったFirecrawlを使ったチャットボットを再び動かす
まとめ
- 次のブロックに渡すFirecrawlの出力をtextからjsonに変更して復活させた
- textだと空データが出力されてしまう
関連リンク
- Firecrawlをセルフホストして、Difyで使う #1
-
Web Clipperを作ってみた - Dify,Chrome拡張,Firecrawl,GPT-4o mini,Notionを活用
- 後述するテンプレートブロック作成の参考にした。
- ちなみにこれまではコードブロックを使っていた。
手順
- CRAWLブロックの次のブロックに渡す変数を
text
からjson
に変更した。
- また次のテンプレートブロックで、最大1万文字でカットオフする。
{{ json[0].data|map(attribute='content')|join(' ')|truncate(10000, true, '') }}
- 無事復活した。

Difyを0.8.3にアップデートする
ゴール
- APIキーのロードバランシングもできるようにする 参考記事
まとめ
- スムーズにアップデートできた。データ引き継ぎも問題なし。
- ロードバランシング機能も有効化できた。(まだ有効にはしていない)
関連リンク
手順
- gitから最新版をpullするまでは 0.7.0へのアップデート と同じ
# difyのdockerフォルダに移動して、起動中の環境を落とす
docker-compose down
# いまのdocker-compose.yamlとか.envファイルを別フォルダにコピー(バックアップ)する
# データバックアップはしない
# 最新バージョンをpullするために、現在のフォルダ状態をスタッシュ
git stash
# mainブランチに切り替え
git checkout main
# リモートのタグ情報を取得
git fetch --tags
# タグ確認
git tag
# ⇒0.8.3まであることを確認
# 最新バージョンをpull
git pull origin main
# docker-compose.yamlと.envファイルを書き換える(後述)
# コンテナを起動
docker-compose up -d
- docker-compose.yamlと.envファイルの変更点:
### 変更1箇所目 #################################
# ロードバランシングを有効化するため
x-shared-env: &shared-api-worker-env
LOG_LEVEL: ${LOG_LEVEL:-INFO}
LOG_FILE: ${LOG_FILE:-}
## 途中省略 ##
SSRF_PROXY_HTTP_URL: ${SSRF_PROXY_HTTP_URL:-http://ssrf_proxy:3128}
SSRF_PROXY_HTTPS_URL: ${SSRF_PROXY_HTTPS_URL:-http://ssrf_proxy:3128}
MODEL_LB_ENABLED: "true" # 追加(ロードバランシングを有効化)
### 変更2,3箇所目 #################################
# The postgres database.
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: ${PGUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
-c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
volumes:
# - ./volumes/db/data:/var/lib/postgresql/data #オリジナル
- postgres_data:/var/lib/postgresql/data #追加(こうしないとエラーになるから)
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
ports: #追加
- "5432:5432" #追加(SQLツールからの接続用)
### 変更4箇所目 #################################
volumes:
oradata:
dify_es01_data:
postgres_data: #追加
# ホストマシンのIPに変更
# ------------------------------
# Common Variables
# ------------------------------
CONSOLE_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
CONSOLE_WEB_URL=http://161.93.+++.++:8880 #オリジナルは空欄
SERVICE_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
APP_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
APP_WEB_URL=http://161.93.+++.++:8880 #オリジナルは空欄
FILES_URL=http://161.93.+++.++:8880 #オリジナルは空欄
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=8880 #オリジナルは80
EXPOSE_NGINX_SSL_PORT=8443 #オリジナルは443

セルフホストしているFirecrawlをv0からv1にアップデートする#1
ゴール
- ローカルPCでセルフホストしているFirecrawlをv0からv1にアップグレードする
- Difyを0.8.3にアップデートしたらFirecrawlツールが使えなくなったため、とりあえずやってみる。
まとめ
- v0のときと症状は変わらず。Difyでナレッジ作成はできるが、ツールが使えない。
- (11/9追記)再構築したら治った
ナレッジ作成画面(問題なし)
改善前の症状
ツール(4種類)でエラーが出るのは解消せず。
認証はされているようだが、、
⇒認証を再設定しようとするとエラーが出る
関連リンク
手順
- 最新バージョンをgithubからpull
- .envファイルを書き換えて、コンテナをbuild&up
# firecrawlフォルダに移動して、起動中の環境を落とす
docker-compose down
# いまのdocker-compose.yamlと.envファイルを別フォルダにコピー(バックアップ)する
# データバックアップはしない
# 最新バージョンをpullするために、現在のフォルダ状態をスタッシュ
git stash
# mainブランチに切り替え
git checkout main
# リモートのタグ情報を取得
git fetch --tags
# タグ確認
git tag
# ⇒v1まであることを確認
# 最新バージョンをpull
git pull origin main
# .envファイルを書き換える(後述)
# docker-compose.yamlは書き換えるところなし
# buildする
docker-compose build
# ⇒時間かかる。待つ。
# コンテナを起動する
docker-compose up -d
無事起動
.envファイル(変更あり)
.env
# ===== Required ENVS ======
NUM_WORKERS_PER_QUEUE=8
PORT=3002
HOST=0.0.0.0
REDIS_URL=redis://redis:6379 #for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
REDIS_RATE_LIMIT_URL=redis://redis:6379 #for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
PLAYWRIGHT_MICROSERVICE_URL=http://playwright-service:3000/html
## To turn on DB authentication, you need to set up supabase.
# USE_DB_AUTHENTICATION=true #オリジナル
USE_DB_AUTHENTICATION=false #変更後
# ===== Optional ENVS ======
# SearchApi key. Head to https://searchapi.com/ to get your API key
SEARCHAPI_API_KEY=
# SearchApi engine, defaults to google. Available options: google, bing, baidu, google_news, etc. Head to https://searchapi.com/ to explore more engines
SEARCHAPI_ENGINE=
# Supabase Setup (used to support DB authentication, advanced logging, etc.)
SUPABASE_ANON_TOKEN=
SUPABASE_URL=
SUPABASE_SERVICE_TOKEN=
# Other Optionals
# use if you've set up authentication and want to test with a real API key
TEST_API_KEY=fc-test #追加
# set if you'd like to test the scraping rate limit
RATE_LIMIT_TEST_API_KEY_SCRAPE=
# set if you'd like to test the crawling rate limit
RATE_LIMIT_TEST_API_KEY_CRAWL=
# set if you'd like to use scraping Be to handle JS blocking
SCRAPING_BEE_API_KEY=
# add for LLM dependednt features (image alt generation, etc.)
OPENAI_API_KEY=
BULL_AUTH_KEY=@
# set if you have a llamaparse key you'd like to use to parse pdfs
LLAMAPARSE_API_KEY=
# set if you'd like to send slack server health status messages
SLACK_WEBHOOK_URL=
# set if you'd like to send posthog events like job logs
POSTHOG_API_KEY=
# set if you'd like to send posthog events like job logs
POSTHOG_HOST=
STRIPE_PRICE_ID_STANDARD=
STRIPE_PRICE_ID_SCALE=
STRIPE_PRICE_ID_STARTER=
STRIPE_PRICE_ID_HOBBY=
STRIPE_PRICE_ID_HOBBY_YEARLY=
STRIPE_PRICE_ID_STANDARD_NEW=
STRIPE_PRICE_ID_STANDARD_NEW_YEARLY=
STRIPE_PRICE_ID_GROWTH=
STRIPE_PRICE_ID_GROWTH_YEARLY=
# set if you'd like to use the fire engine closed beta
FIRE_ENGINE_BETA_URL=
# Proxy Settings for Playwright (Alternative you can can use a proxy service like oxylabs, which rotates IPs for you on every request)
PROXY_SERVER=
PROXY_USERNAME=
PROXY_PASSWORD=
# set if you'd like to block media requests to save proxy bandwidth
BLOCK_MEDIA=
# Set this to the URL of your webhook when using the self-hosted version of FireCrawl
SELF_HOSTED_WEBHOOK_URL=
# Resend API Key for transactional emails
RESEND_API_KEY=
# LOGGING_LEVEL determines the verbosity of logs that the system will output.
# Available levels are:
# NONE - No logs will be output.
# ERROR - For logging error messages that indicate a failure in a specific operation.
# WARN - For logging potentially harmful situations that are not necessarily errors.
# INFO - For logging informational messages that highlight the progress of the application.
# DEBUG - For logging detailed information on the flow through the system, primarily used for debugging.
# TRACE - For logging more detailed information than the DEBUG level.
# Set LOGGING_LEVEL to one of the above options to control logging output.
LOGGING_LEVEL=INFO
docker-compose.yamlファイル(変更していません)
docker-compose.yaml
name: firecrawl
x-common-service: &common-service
build: apps/api
networks:
- backend
extra_hosts:
- "host.docker.internal:host-gateway"
services:
playwright-service:
build: apps/playwright-service
environment:
- PORT=3000
- PROXY_SERVER=${PROXY_SERVER}
- PROXY_USERNAME=${PROXY_USERNAME}
- PROXY_PASSWORD=${PROXY_PASSWORD}
- BLOCK_MEDIA=${BLOCK_MEDIA}
networks:
- backend
api:
<<: *common-service
environment:
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
REDIS_RATE_LIMIT_URL: ${REDIS_URL:-redis://redis:6379}
PLAYWRIGHT_MICROSERVICE_URL: ${PLAYWRIGHT_MICROSERVICE_URL:-http://playwright-service:3000}
USE_DB_AUTHENTICATION: ${USE_DB_AUTHENTICATION}
PORT: ${PORT:-3002}
NUM_WORKERS_PER_QUEUE: ${NUM_WORKERS_PER_QUEUE}
OPENAI_API_KEY: ${OPENAI_API_KEY}
OPENAI_BASE_URL: ${OPENAI_BASE_URL}
MODEL_NAME: ${MODEL_NAME:-gpt-4o}
SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL}
LLAMAPARSE_API_KEY: ${LLAMAPARSE_API_KEY}
LOGTAIL_KEY: ${LOGTAIL_KEY}
BULL_AUTH_KEY: ${BULL_AUTH_KEY}
TEST_API_KEY: ${TEST_API_KEY}
POSTHOG_API_KEY: ${POSTHOG_API_KEY}
POSTHOG_HOST: ${POSTHOG_HOST}
SUPABASE_ANON_TOKEN: ${SUPABASE_ANON_TOKEN}
SUPABASE_URL: ${SUPABASE_URL}
SUPABASE_SERVICE_TOKEN: ${SUPABASE_SERVICE_TOKEN}
SCRAPING_BEE_API_KEY: ${SCRAPING_BEE_API_KEY}
HOST: ${HOST:-0.0.0.0}
SELF_HOSTED_WEBHOOK_URL: ${SELF_HOSTED_WEBHOOK_URL}
LOGGING_LEVEL: ${LOGGING_LEVEL}
FLY_PROCESS_GROUP: app
depends_on:
- redis
- playwright-service
ports:
- "3002:3002"
command: [ "pnpm", "run", "start:production" ]
worker:
<<: *common-service
environment:
REDIS_URL: ${REDIS_URL:-redis://redis:6379}
REDIS_RATE_LIMIT_URL: ${REDIS_URL:-redis://redis:6379}
PLAYWRIGHT_MICROSERVICE_URL: ${PLAYWRIGHT_MICROSERVICE_URL:-http://playwright-service:3000}
USE_DB_AUTHENTICATION: ${USE_DB_AUTHENTICATION}
PORT: ${PORT:-3002}
NUM_WORKERS_PER_QUEUE: ${NUM_WORKERS_PER_QUEUE}
OPENAI_API_KEY: ${OPENAI_API_KEY}
OPENAI_BASE_URL: ${OPENAI_BASE_URL}
MODEL_NAME: ${MODEL_NAME:-gpt-4o}
SLACK_WEBHOOK_URL: ${SLACK_WEBHOOK_URL}
LLAMAPARSE_API_KEY: ${LLAMAPARSE_API_KEY}
LOGTAIL_KEY: ${LOGTAIL_KEY}
BULL_AUTH_KEY: ${BULL_AUTH_KEY}
TEST_API_KEY: ${TEST_API_KEY}
POSTHOG_API_KEY: ${POSTHOG_API_KEY}
POSTHOG_HOST: ${POSTHOG_HOST}
SUPABASE_ANON_TOKEN: ${SUPABASE_ANON_TOKEN}
SUPABASE_URL: ${SUPABASE_URL}
SUPABASE_SERVICE_TOKEN: ${SUPABASE_SERVICE_TOKEN}
SCRAPING_BEE_API_KEY: ${SCRAPING_BEE_API_KEY}
HOST: ${HOST:-0.0.0.0}
SELF_HOSTED_WEBHOOK_URL: ${SELF_HOSTED_WEBHOOK_URL}
LOGGING_LEVEL: ${LOGGING_LEVEL}
FLY_PROCESS_GROUP: worker
depends_on:
- redis
- playwright-service
- api
command: [ "pnpm", "run", "workers" ]
redis:
image: redis:alpine
networks:
- backend
command: redis-server --bind 0.0.0.0
networks:
backend:
driver: bridge

Dify0.9.0でRAG検索できないエラー発生
ゴール
- 0.8.3から0.9.0にアップデートしたら知識獲得ツールでエラーが出るようになったのを対処する。
Run failed: '<' not supported between instances of 'NoneType' and 'NoneType'
まとめ
- 0.9.0から0.9.1にアップデートしたら治った。
参考リンク
- 公式リポジトリのIssueで見つけた同じ不具合
手順
- 0.8.3へのアップデート方法と同じなので割愛

Dify0.10.0にアップデートする
ゴール
- 0.10.0にアップデートする
まとめ
- スムーズにアップデートできた。データ引き継ぎも問題なし。
参考リンク
- 公式リポジトリのリリースノート
- 公式Doc: ファイルアップロード
- 公式Doc: ファイルアップロードを使用した記事理解アシスタントの構築方法
- 公式Blog: 新機能を利用してNotebookLMのようなAIポッドキャストアプリを作成する方法
手順
- いつもは単なる最新版へのupdateだが、今回は0.10.0bata2から0.10.0にする
# firecrawlフォルダに移動して、起動中の環境を落とす
docker-compose down
# いまのdocker-compose.yamlと.envファイルを別フォルダにコピー(バックアップ)する
# データバックアップはしない
# 最新バージョンをpullするために、現在のフォルダ状態をスタッシュ
git stash
# mainブランチに切り替え
git checkout main
# リモートのタグ情報を取得
git fetch --tags
# タグ確認
git tag
# ⇒0.10.0まであることを確認
# 最新バージョンまでpull
git pull origin main
# ===最新版にするだけなら不要(ここから)===
# 0.10.0タグに切り替え
git checkout tags/0.10.0
# ===最新版にするだけなら不要(ここまで)===
# docker-compose.yamlと.envファイルを書き換える(後述)
# コンテナを起動する
docker-compose up -d
⇒無事起動。
- docker-compose.yamlと.envファイルの変更点:
### 変更1箇所目 #################################
# ロードバランシングを有効化するため
x-shared-env: &shared-api-worker-env
LOG_LEVEL: ${LOG_LEVEL:-INFO}
LOG_FILE: ${LOG_FILE:-}
## 途中省略 ##
SSRF_PROXY_HTTP_URL: ${SSRF_PROXY_HTTP_URL:-http://ssrf_proxy:3128}
SSRF_PROXY_HTTPS_URL: ${SSRF_PROXY_HTTPS_URL:-http://ssrf_proxy:3128}
MODEL_LB_ENABLED: "true" # 追加(ロードバランシングを有効化)
### 変更2,3箇所目 #################################
# The postgres database.
db:
image: postgres:15-alpine
restart: always
environment:
PGUSER: ${PGUSER:-postgres}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-difyai123456}
POSTGRES_DB: ${POSTGRES_DB:-dify}
PGDATA: ${PGDATA:-/var/lib/postgresql/data/pgdata}
command: >
postgres -c 'max_connections=${POSTGRES_MAX_CONNECTIONS:-100}'
-c 'shared_buffers=${POSTGRES_SHARED_BUFFERS:-128MB}'
-c 'work_mem=${POSTGRES_WORK_MEM:-4MB}'
-c 'maintenance_work_mem=${POSTGRES_MAINTENANCE_WORK_MEM:-64MB}'
-c 'effective_cache_size=${POSTGRES_EFFECTIVE_CACHE_SIZE:-4096MB}'
volumes:
# - ./volumes/db/data:/var/lib/postgresql/data #オリジナル
- postgres_data:/var/lib/postgresql/data #追加(こうしないとエラーになるから)
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 1s
timeout: 3s
retries: 30
ports: #追加
- "5432:5432" #追加(SQLツールからの接続用)
### 変更4箇所目 #################################
volumes:
oradata:
dify_es01_data:
postgres_data: #追加
# ホストマシンのIPに変更
# ------------------------------
# Common Variables
# ------------------------------
CONSOLE_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
CONSOLE_WEB_URL=http://161.93.+++.++:8880 #オリジナルは空欄
SERVICE_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
APP_API_URL=http://161.93.+++.++:8880 #オリジナルは空欄
APP_WEB_URL=http://161.93.+++.++:8880 #オリジナルは空欄
FILES_URL=http://161.93.+++.++:8880 #オリジナルは空欄
# ------------------------------
# Docker Compose Service Expose Host Port Configurations
# ------------------------------
EXPOSE_NGINX_PORT=8880 #オリジナルは80
EXPOSE_NGINX_SSL_PORT=8443 #オリジナルは443

Dify0.11.0にアップデートする
ゴール
- 0.11.0にアップデートする
まとめ
- middlewareを稼働させたままアップデートしたら、ナレッジのドキュメント取り込みができなくなった。(過去にもあった現象)
- ⇒ middlewareを停止して、Difyを再起動したら治った。
- 並列イテレーションが実装されて、アプリが高速化した!
参考リンク
手順
- 0.10.0にアップデートしたときと同じなので割愛

チャットアプリAPIをまとめる
ゴール
- APIアクセスページのサンプルcurlコードをPythonコードにしてまとめる
まとめ
-
curlコードをPythonコードへの変換はChatGPTにしてもらった。
-
できることは以下のとおり
- チャットメッセージ送信
- ファイルアップロード
- 音声認識 (Speech to Text)
- 音声合成 (Text to Speech)
- 会話履歴取得
- 会話削除
- 会話の名前変更
- 推奨質問取得
- アプリ情報取得
- アプリメタ情報取得
-
アプリ毎に固定のAPIキー、任意に決められるuser、会話セッション毎に割り振られる(=ユーザーでなくDifyが決める)conversation_idを使えば、セッション中の会話メモリ管理、会話履歴の保存、会話履歴の呼び出しと削除がAPIでできる⇒streamlitなどにDifyチャットボットフローを埋め込んだ高度なアプリが作れる。
参考リンク
- 公式Doc Developing with APIs 、、、ざっとしか書いていない
手順
-
Difyでチャットボットを作る
-
APIアクセスページで APIサーバURLをコピー
-
APIキーを作成してコピー
-
以下のサンプルコードを使いこなす!
APIサンプルコード一覧
import requests
# APIキーとベースURL
API_KEY = "++++++++++++" #アプリ毎に違う
BASE_URL = "http://161.93.+++.+++:8880/v1" #Dify環境で固定
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# 1. チャットメッセージ送信
def send_chat_message(query, user_id, conversation_id=None, response_mode="blocking"):
"""
Parameters:
- query (str): ユーザー入力
- user_id (str): ユーザーID
- conversation_id (str, optional): 会話ID。最初の回答で返ってくる。空にすると新しい会話になる。
- response_mode (str): "blocking" または "streaming"
- それ以外の引数はinputsで渡す(割愛)
"""
url = f"{BASE_URL}/chat-messages"
payload = {
"query": query,
"user": user_id,
"conversation_id": conversation_id,
"response_mode": response_mode
}
return requests.post(url, json=payload, headers=HEADERS).json()
# 2. ファイルアップロード
def upload_file(file_path, user_id):
"""
Parameters:
- file_path (str): ファイルのパス
- user_id (str): ユーザーID
"""
url = f"{BASE_URL}/files/upload"
with open(file_path, 'rb') as file:
files = {"file": file}
data = {"user": user_id}
return requests.post(url, headers={"Authorization": f"Bearer {API_KEY}"}, files=files, data=data).json()
# 3. 音声認識 (Speech to Text)
def speech_to_text(file_path, user_id):
"""
Parameters:
- file_path (str): 音声ファイルのパス
- user_id (str): ユーザーID
"""
url = f"{BASE_URL}/audio-to-text"
with open(file_path, 'rb') as audio_file:
files = {"file": audio_file}
data = {"user": user_id}
return requests.post(url, headers={"Authorization": f"Bearer {API_KEY}"}, files=files, data=data).json()
# 4. 音声合成 (Text to Speech)
def text_to_audio(text, user_id, message_id=None):
"""
Parameters:
- text (str): 音声化するテキスト
- user_id (str): ユーザーID
- message_id (str, optional): Difyが生成したメッセージID(優先使用)
"""
url = f"{BASE_URL}/text-to-audio"
payload = {"text": text, "user": user_id, "message_id": message_id}
response = requests.post(url, json=payload, headers=HEADERS)
return response.content # 音声データ
# 5. 会話履歴取得
def get_conversation_history(user_id, conversation_id, limit=20):
"""
Parameters:
- user_id (str): ユーザーID
- conversation_id (str): 会話ID
- limit (int): 最大取得件数
"""
url = f"{BASE_URL}/messages"
params = {"user": user_id, "conversation_id": conversation_id, "limit": limit}
return requests.get(url, headers=HEADERS, params=params).json()
# 6. メッセージ削除
def delete_conversation(user_id, conversation_id):
"""
Parameters:
- user_id (str): ユーザーID
- conversation_id (str): 削除対象の会話ID
"""
url = f"{BASE_URL}/conversations/{conversation_id}"
payload = {"user": user_id}
return requests.delete(url, json=payload, headers=HEADERS).json()
# 7. 会話の名前変更
def rename_conversation(user_id, conversation_id, new_name):
"""
Parameters:
- user_id (str): ユーザーID
- conversation_id (str): 対象の会話ID
- new_name (str): 新しい名前
"""
url = f"{BASE_URL}/conversations/{conversation_id}/name"
payload = {"user": user_id, "name": new_name}
return requests.post(url, json=payload, headers=HEADERS).json()
# 8. 推奨質問の取得
def get_suggested_questions(user_id, message_id):
"""
Parameters:
- user_id (str): ユーザーID
- message_id (str): メッセージID
"""
url = f"{BASE_URL}/messages/{message_id}/suggested"
params = {"user": user_id}
return requests.get(url, headers=HEADERS, params=params).json()
# 9. アプリ情報取得
def get_app_info(user_id):
"""
Parameters:
- user_id (str): ユーザーID
"""
url = f"{BASE_URL}/parameters"
params = {"user": user_id}
return requests.get(url, headers=HEADERS, params=params).json()
# 10. アプリメタ情報取得
def get_meta_info(user_id):
"""
Parameters:
- user_id (str): ユーザーID
"""
url = f"{BASE_URL}/meta"
params = {"user": user_id}
return requests.get(url, headers=HEADERS, params=params).json()
# メイン処理例
if __name__ == "__main__":
print(send_chat_message("What is AI?", "user123"))
print(upload_file("path/to/file.png", "user123"))
print(speech_to_text("path/to/audio.mp3", "user123"))
print(text_to_audio("Hello, world!", "user123"))
print(get_conversation_history("user123", "conversation_id_here"))
print(delete_conversation("user123", "conversation_id_here"))
print(rename_conversation("user123", "conversation_id_here", "New Name"))
print(get_suggested_questions("user123", "message_id_here"))
print(get_app_info("user123"))
print(get_meta_info("user123"))
- レスポンスはjsonで返ってくる。
- たとえばsend_chat_message(blockingモード)ならば回答は
answer
キーに格納されているので、回答だけ表示したいときは以下のようになる。(詳細割愛)
- たとえばsend_chat_message(blockingモード)ならば回答は
response = send_chat_message("What is AI?", "user123")
answer = response.get("answer", "No answer found")
print(answer)

Firecrawlをアップデートする
ゴール
- セルフホストしてDockerコンテナで稼働中のFirecrawlをアップデートする
- 実際には2024年9月のv1リリースからバージョンアップしていないので備忘録
まとめ
- リポジトリに含まれている SELF_HOST.md を日本語にした。
SELF_HOST.md日本語訳
Firecrawl のセルフホスティング
コントリビューターですか?
Firecrawl 🔥 へようこそ!こちらでは、プロジェクトをローカルにセットアップして自分で実行し、貢献するための手順を説明します。
コントリビュートする場合、プロセスは他のオープンソースリポジトリと似ており、Firecrawl をフォークし、変更を加え、テストを実行し、プルリクエスト(PR)を送信します。
質問がある場合やセットアップのサポートが必要な場合は、こちら のDiscordコミュニティに参加するか、こちら でGitHubにイシューを提出してください!
なぜセルフホスティングをするのか?
Firecrawl をセルフホスティングすることは、データを制御された環境内に留める必要がある厳格なセキュリティポリシーを持つ組織にとって特に有益です。セルフホスティングを検討する主な理由は以下の通りです:
- セキュリティとコンプライアンスの強化: セルフホスティングにより、すべてのデータ処理が内部および外部の規制に準拠し、機密情報を安全なインフラ内に保持できます。FirecrawlはMendable製品であり、SOC2 Type2認証に依存しているため、データセキュリティ管理において高い業界標準を遵守しています。
- サービスのカスタマイズ: セルフホスティングにより、Playwrightサービスなどのサービスを特定のニーズや標準のクラウド提供ではサポートされていない特定のユースケースに合わせて調整できます。
- 学習とコミュニティへの貢献: 自身のインスタンスをセットアップし維持することで、Firecrawlの仕組みをより深く理解でき、プロジェクトへのより有意義な貢献が可能になります。
考慮事項
ただし、以下の制限や追加の責任事項にも注意が必要です:
- Fire-engineへのアクセス制限: 現在、セルフホスティングされたFirecrawlのインスタンスはFire-engineへのアクセスがありません。Fire-engineにはIPブロックの管理やロボット検出メカニズムなどの高度な機能が含まれます。基本的なスクレイピングタスクは管理できますが、より複雑なシナリオでは追加の設定が必要となる場合やサポートされない場合があります。
-
手動での設定が必要: 基本的なfetchやPlaywrightオプション以外のスクレイピング方法を使用する場合、
.env
ファイルでこれらを手動で設定する必要があります。これは技術の深い理解を必要とし、セットアップに時間がかかる場合があります。
Firecrawlのセルフホスティングは、スクレイピングおよびデータ処理環境を完全に管理したい方に最適ですが、追加のメンテナンスおよび設定作業が伴います。
手順
-
まず、依存関係をインストールします
- Docker の インストール手順 を参照してください。
-
環境変数を設定します
ルートディレクトリに
.env
ファイルを作成し、apps/api/.env.example
のテンプレートをコピーします。認証やオプションのサブサービス(PDFパース、JSブロッキングサポート、AI機能)は設定しません。
.env:
の内容は以下の通りです:# ===== 必須の環境変数 ====== NUM_WORKERS_PER_QUEUE=8 PORT=3002 HOST=0.0.0.0 REDIS_URL=redis://redis:6379 REDIS_RATE_LIMIT_URL=redis://redis:6379 ## DB認証を有効にするには、Supabaseを設定する必要があります。 USE_DB_AUTHENTICATION=false # ===== オプションの環境変数 ====== # Supabaseの設定(DB認証、詳細なロギングなどをサポート) SUPABASE_ANON_TOKEN= SUPABASE_URL= SUPABASE_SERVICE_TOKEN= # その他のオプション TEST_API_KEY= # 認証を設定し、実際のAPIキーでテストする場合に使用 SCRAPING_BEE_API_KEY= # フォールバックスクレイパーとして使用する場合に設定 OPENAI_API_KEY= # LLM依存機能(例:画像のalt生成)用に追加 BULL_AUTH_KEY= @ PLAYWRIGHT_MICROSERVICE_URL= # Playwrightフォールバックを実行する場合に設定 LLAMAPARSE_API_KEY= # PDFをパースするためにllamaparseキーを使用する場合に設定 SLACK_WEBHOOK_URL= # サーバーのヘルスステータスメッセージをSlackに送信する場合に設定 POSTHOG_API_KEY= # ジョブログなどのPosthogイベントを送信する場合に設定 POSTHOG_HOST= # ジョブログなどのPosthogイベントを送信する場合に設定
-
(オプション)TypeScript Playwrightサービスを使用する場合
-
docker-compose.yml
ファイルを更新し、Playwrightサービスを変更します:build: apps/playwright-service
から
build: apps/playwright-service-ts
に変更します。
-
.env
ファイルにPLAYWRIGHT_MICROSERVICE_URL
を設定します:PLAYWRIGHT_MICROSERVICE_URL=http://localhost:3000/scrape
-
必要に応じて
.env
ファイルにプロキシサーバーを設定することを忘れないでください。
-
-
Dockerコンテナをビルドして実行します
docker compose build docker compose up
これにより、
http://localhost:3002
でアクセス可能なローカルインスタンスのFirecrawlが実行されます。http://localhost:3002/admin/@/queues
でBull Queue Manager UIを確認できます。 -
(オプション)APIをテストする
クロールエンドポイントをテストしたい場合、以下を実行できます:
curl -X POST http://localhost:3002/v1/crawl \ -H 'Content-Type: application/json' \ -d '{ "url": "https://mendable.ai" }'
トラブルシューティング
このセクションでは、セルフホストされたFirecrawlインスタンスのセットアップや実行中に遭遇する一般的な問題への解決策を提供します。
Supabaseクライアントが設定されていない
症状:
[YYYY-MM-DDTHH:MM:SS.SSSz]ERROR - Attempted to access Supabase client when it's not configured.
[YYYY-MM-DDTHH:MM:SS.SSSz]ERROR - Error inserting scrape event: Error: Supabase client is not configured.
説明:
このエラーはSupabaseクライアントのセットアップが完了していないために発生します。スクレイプとクロールは問題なく実行できますが、現在セルフホスティングされたインスタンスではSupabaseの設定はできません。
認証をバイパスしています
症状:
[YYYY-MM-DDTHH:MM:SS.SSSz]WARN - You're bypassing authentication
説明:
このエラーはSupabaseクライアントのセットアップが完了していないために発生します。スクレイプとクロールは問題なく実行できますが、現在セルフホスティングされたインスタンスではSupabaseの設定はできません。
Dockerコンテナが起動しない
症状:
Dockerコンテナが予期せず終了する、または起動に失敗する。
解決策:
以下のコマンドを使用してDockerログを確認し、エラーメッセージを確認します:
docker logs [コンテナ名]
-
.env
ファイル内のすべての必要な環境変数が正しく設定されていることを確認してください。 -
docker-compose.yml
に定義されたすべてのDockerサービスが正しく設定され、必要なイメージが利用可能であることを確認してください。
Redisとの接続問題
症状:
Redisへの接続に関連するエラー(タイムアウトや「接続拒否」など)が発生する。
解決策:
- Docker環境でRedisサービスが稼働していることを確認してください。
-
.env
ファイル内のREDIS_URL
およびREDIS_RATE_LIMIT_URL
が正しいRedisインスタンスを指していることを確認し、docker-compose.yaml
ファイル内でも同じURL(redis://redis:6379
)を指していることを確認してください。 - Redisポートへの接続をブロックするネットワーク設定やファイアウォールルールがないか確認してください。
APIエンドポイントが応答しない
症状:
FirecrawlインスタンスへのAPIリクエストがタイムアウトする、または応答がない。
解決策:
- Dockerコンテナのステータスを確認し、Firecrawlサービスが実行中であることを確認してください。
-
.env
ファイル内のPORT
およびHOST
設定が正しく、他のサービスが同じポートを使用していないことを確認してください。 - APIリクエストを行うクライアントからホストがアクセス可能であることを確認するためにネットワーク設定をチェックしてください。
これらの一般的な問題に対処することで、セルフホストされたFirecrawlインスタンスのセットアップと運用をスムーズに行うことができます。
KubernetesクラスターへのFirecrawlインストール(簡易版)
KubernetesクラスターにFirecrawlをインストールする方法については、examples/kubernetes/cluster-install/README.md を参照してください。
参考リンク
- セルフホストの注意事項まとめ
セルフホストの注意事項まとめ
以下は、Firecrawl をセルフホスティングする際の注意事項の要約です。
セルフホスティング時の注意事項
-
Fire-engineへのアクセス制限
- セルフホストされた Firecrawl インスタンスは Fire-engine へのアクセスがありません。
- IPブロックの管理やロボット検出メカニズムなどの高度な機能が利用できません。
- 基本的なスクレイピングタスクは可能ですが、複雑なシナリオでは追加の設定が必要になる場合があります。
-
手動での設定が必要
- 基本的な
fetch
やPlaywright
オプション以外のスクレイピング方法を使用する場合、.env
ファイルで手動設定が必要です。 - これには技術的な理解が求められ、セットアップに時間がかかる可能性があります。
- 基本的な
-
追加のメンテナンスと管理
- セルフホスティングは完全な制御を提供しますが、その分メンテナンスや管理作業が増えます。
- 定期的なアップデートやセキュリティパッチの適用が必要です。
-
データのバックアップ
- バージョンアップや設定変更前に、データベースや重要なデータのバックアップを取ることを推奨します。
-
依存関係と環境設定の確認
-
.env
ファイル以外にも、docker-compose.yml
や他の設定ファイルの依存関係を確認・更新する必要があります。 - 必要な環境変数が正しく設定されていることを確認してください。
-
-
セキュリティの確保
- データを安全に保つために、適切なセキュリティ対策(ファイアウォール設定、アクセス制御など)を講じてください。
- 機密情報が漏洩しないよう、環境変数や設定ファイルの管理に注意が必要です。
-
リソースの管理
- Docker コンテナやサービスが適切に動作しているか、リソース使用状況を監視してください。
- 必要に応じて、不要な Docker リソースのクリーンアップを行い、ディスクスペースを確保します。
これらの注意事項を遵守することで、Firecrawl のセルフホスティングを安全かつ効果的に行うことができます。問題が発生した場合は、公式ドキュメントやコミュニティリソースを参照してください。
関連リンク
手順
設定画面
# git cloneしたfirecrawlフォルダでPoserShellを起動してコンテナを停止
docker-compose down
# 現在のフォルダ状態をスタッシュ
git stash
# 最新リポジトリをダウンロード
git pull origin main
# .envサンプルファイルをコピー
cp ./apps/api/.env.example .env
# .envファイルを修正(後述)
# コンテナをビルド(時間かかる)
docker-compose build
# コンテナを起動
docker-compose up -d
- docker-compose.yamlファイルはそのまま。
- .envファイルは以下を変更。
.envファイル
# ===== Required ENVS ======
NUM_WORKERS_PER_QUEUE=8
PORT=3002
HOST=0.0.0.0
REDIS_URL=redis://redis:6379 #for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
REDIS_RATE_LIMIT_URL=redis://redis:6379 #for self-hosting using docker, use redis://redis:6379. For running locally, use redis://localhost:6379
PLAYWRIGHT_MICROSERVICE_URL=http://playwright-service:3000/html
## To turn on DB authentication, you need to set up supabase.
USE_DB_AUTHENTICATION=false #変更 オリジナルはtrue
# ===== Optional ENVS ======
# SearchApi key. Head to https://searchapi.com/ to get your API key
SEARCHAPI_API_KEY=
# SearchApi engine, defaults to google. Available options: google, bing, baidu, google_news, etc. Head to https://searchapi.com/ to explore more engines
SEARCHAPI_ENGINE=
# Supabase Setup (used to support DB authentication, advanced logging, etc.)
SUPABASE_ANON_TOKEN=
SUPABASE_URL=
SUPABASE_SERVICE_TOKEN=
# Other Optionals
# use if you've set up authentication and want to test with a real API key
TEST_API_KEY=fc-test #テスト。オリジナルは空欄
# set if you'd like to test the scraping rate limit
RATE_LIMIT_TEST_API_KEY_SCRAPE=
# set if you'd like to test the crawling rate limit
RATE_LIMIT_TEST_API_KEY_CRAWL=
# set if you'd like to use scraping Be to handle JS blocking
SCRAPING_BEE_API_KEY=
# add for LLM dependednt features (image alt generation, etc.)
OPENAI_API_KEY=
BULL_AUTH_KEY=@
# set if you have a llamaparse key you'd like to use to parse pdfs
LLAMAPARSE_API_KEY=
# set if you'd like to send slack server health status messages
SLACK_WEBHOOK_URL=
# set if you'd like to send posthog events like job logs
POSTHOG_API_KEY=
# set if you'd like to send posthog events like job logs
POSTHOG_HOST=
STRIPE_PRICE_ID_STANDARD=
STRIPE_PRICE_ID_SCALE=
STRIPE_PRICE_ID_STARTER=
STRIPE_PRICE_ID_HOBBY=
STRIPE_PRICE_ID_HOBBY_YEARLY=
STRIPE_PRICE_ID_STANDARD_NEW=
STRIPE_PRICE_ID_STANDARD_NEW_YEARLY=
STRIPE_PRICE_ID_GROWTH=
STRIPE_PRICE_ID_GROWTH_YEARLY=
# set if you'd like to use the fire engine closed beta
FIRE_ENGINE_BETA_URL=
# Proxy Settings for Playwright (Alternative you can can use a proxy service like oxylabs, which rotates IPs for you on every request)
PROXY_SERVER=
PROXY_USERNAME=
PROXY_PASSWORD=
# set if you'd like to block media requests to save proxy bandwidth
BLOCK_MEDIA=
# Set this to the URL of your webhook when using the self-hosted version of FireCrawl
SELF_HOSTED_WEBHOOK_URL=
# Resend API Key for transactional emails
RESEND_API_KEY=
# LOGGING_LEVEL determines the verbosity of logs that the system will output.
# Available levels are:
# NONE - No logs will be output.
# ERROR - For logging error messages that indicate a failure in a specific operation.
# WARN - For logging potentially harmful situations that are not necessarily errors.
# INFO - For logging informational messages that highlight the progress of the application.
# DEBUG - For logging detailed information on the flow through the system, primarily used for debugging.
# TRACE - For logging more detailed information than the DEBUG level.
# Set LOGGING_LEVEL to one of the above options to control logging output.
LOGGING_LEVEL=INFO

DifyアプリとAPI連携したstreamlitチャットボットを作る
ゴール
- DifyチャットボットとAPI連携して、メモリ管理や会話履歴をDifyに任せるstreamlitチャットボットを作ってみる。
- 画像をアップロードして、それとチャットできるようにする。
まとめ
- メモリ管理、会話履歴管理をDifyがしてくれるのは楽。
- 会話履歴からチャットを再開すると画像サムネイルが表示されない...
- 画像とチャットするには、最初に画像をアップロードして画像IDを取得、次に画像IDを引数にして画像を参照しながらチャット、、という流れと分かった。
- 頑張れば、ChatGPT ProjectsやGoogle NotebookLMのクローンが作れそう。
関連リンク
- Difyアプリの「APIアクセス」
※いつの間にか日本語表記になっていた
手順
- Difyでチャットボットを作って公開する。(Difyバージョンは0.14.2)
- API接続を有効にして、APIキーを取得する。
- streamlitチャットボットのコードを書く。
streamlitチャットボットのコード
import streamlit as st
import requests
import json
import logging
import time
# -----------------------------------------------------
# もろもろの設定
# -----------------------------------------------------
st.set_page_config(page_title="Dify連携Chatbot", page_icon="🤖", layout="wide")
st.sidebar.title("🤖Dify連携Chatbot")
# ロギングの設定
logging.basicConfig(level=logging.ERROR)
# グローバル変数の設定
DIFY_URL = 'http://161.93.+++.++:8080' #ローカルホストしているDifyのURL
API_KEY = 'app-b5KlVbjKAC0wjgu+++++' #アプリ毎に振り出されるAPIキー
HEADERS = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
def send_message_to_dify(
user_message,
user_id,
conversation_id="",
file_id=""):
"""
Difyチャットボットのエンドポイントとメッセージを送受信する。
"""
url = f'{DIFY_URL}/v1/chat-messages'
if file_id != "":
payload = {
"inputs": {},
"query": user_message,
"response_mode": "blocking",
"conversation_id": conversation_id,
"user": user_id,
"files": [{
"type": "image",
"transfer_method": "local_file",
"upload_file_id": file_id
}]
}
else:
payload = {
"inputs": {},
"query": user_message,
"response_mode": "blocking",
"conversation_id": conversation_id,
"user": user_id
}
try:
response = requests.post(url, headers=HEADERS, json=payload)
except requests.exceptions.RequestException as e:
logging.error(f"HTTPリクエストエラー: {e}")
st.write('リクエストエラーが発生しました。')
return response.json()
def upload_image_to_dify(upload_image, user_id):
"""
Difyに画像をアップロードする。
画像のIDが返される。
"""
url = f'{DIFY_URL}/v1/files/upload'
headers = {'Authorization': f'Bearer {API_KEY}'}
files = {"file": (upload_image.name, upload_image.getvalue(), upload_image.type)}
data = {'user': user_id}
with st.spinner("画像をアップロード中..."):
try:
response = requests.post(url, headers=headers, files=files, data=data)
except requests.exceptions.RequestException as e:
st.error(f"リクエストに失敗しました: {e}")
return None
if response.status_code in (200, 201):
upload_data = response.json()
# ファイルIDを取得して返す
return upload_data.get("id")
def dify_get_messages(user_id="tico-data-import-python", conversation_id=""):
"""
ユーザーIDと会話IDから会話履歴を取得する。
"""
url = f'{DIFY_URL}/v1/messages'
params = {
"user": user_id,
"conversation_id": conversation_id,
"limit": 20
}
response = requests.get(url, headers=HEADERS, params=params)
if response.status_code == 200:
return response.json().get('data', [])
else:
st.write(f"Error: {response.status_code}, {response.text}")
return []
def dify_get_conversations(user_id, DIFY_URL=DIFY_URL, HEADERS=HEADERS):
"""
指定されたユーザーIDに基づいて会話リストを取得する関数。
"""
url = f'{DIFY_URL}/v1/conversations'
params = {
'user': user_id,
'last_id': '', # default is null
'limit': 20 # 取得する会話の数
}
# GETリクエストを送信
response = requests.get(url, headers=HEADERS, params=params)
# JSON形式でレスポンスが返される場合は、以下のように解析
try:
json_response = response.json()
conversation_id_list = result = [{'id': item['id'], 'name': item['name']} for item in json_response['data']]
except ValueError:
print("JSON形式ではないレスポンス:", response.text)
return conversation_id_list
def dify_delete_conversation(user_id, conversation_id):
"""
指定された会話を削除する。
"""
url = f"{DIFY_URL}/v1/conversations/{conversation_id}"
data = {"user": user_id}
try:
# DELETEリクエストを送信
response = requests.delete(url, headers=HEADERS, data=json.dumps(data))
# # # レスポンスのステータスコードと内容をログに出力
logging.debug(f"DELETEステータスコード: {response.status_code}")
logging.debug(f"DELETEレスポンス: {response.json()}")
# ステータスコードに応じた処理
if response.status_code in [200, 204]:
st.success("会話を削除します。")
time.sleep(2)
st.session_state.conversations = dify_get_conversations(user_id=user_id)
st.rerun()
return True
else:
st.error("会話の削除に失敗しました。")
time.sleep(2)
return False
except requests.exceptions.RequestException as e:
logging.error(f"HTTPリクエストエラー: {e}")
st.error("リクエストエラーが発生しました。")
time.sleep(2)
return False
def dify_rename_conversation(user_id, conversation_id, new_name):
"""
会話名を変更する。
"""
url = f"{DIFY_URL}/v1/conversations/{conversation_id}/name"
payload = {
"name": new_name,
"user": user_id
}
try:
response = requests.post(url, json=payload)
logging.debug(f"POSTステータスコード: {response.status_code}")
logging.debug(f"POSTレスポンス: {response.json()}")
if response.json().get("name") == new_name:
st.success("会話名を変更します。")
time.sleep(2)
st.session_state.conversations = dify_get_conversations(user_id=user_id)
st.rerun()
return True
else:
st.error("会話名の変更に失敗しました。")
time.sleep(2)
return False
except requests.exceptions.RequestException as e:
logging.error(f"HTTPリクエストエラー: {e}")
st.error("リクエストエラーが発生しました。")
time.sleep(2)
return False
def dify_chatbot():
"""
メイン関数
"""
# -----------------------------------------------------
# session_stateの初期化
# -----------------------------------------------------
if 'conversation_id' not in st.session_state:
st.session_state.conversation_id = ""
if 'messages' not in st.session_state:
st.session_state.messages = []
if 'file_id' not in st.session_state:
st.session_state.file_id = ""
# -----------------------------------------------------
# 会話の準備
# ------------------------------------------------
# ユーザーIDの入力
user_id = st.sidebar.text_input("ユーザーID", "")
if not user_id:
st.sidebar.info("👆会話履歴管理のため、従業員番号を入力してください。")
st.stop()
st.sidebar.write(f"ユーザーID: {user_id}")
st.sidebar.write(f"会話ID: {st.session_state.conversation_id}")
# 会話リセットボタンの追加
if st.sidebar.button("会話をリセット"):
st.session_state.conversation_id = ""
st.session_state.messages = []
st.rerun()
# -----------------------------------------------------
# チャットメッセージを表示
# -----------------------------------------------------
# for message in st.session_state.messages:
# avatar = "😎" if message['role'] == "user" else "🎅"
# st.chat_message(message['role'], avatar=avatar).write(message['content'])
# # -----------------------------------------------------
# # messagesをメイン画面に表示(チャット形式)
# # -----------------------------------------------------
for msg in st.session_state.messages:
if msg["role"] == "user":
if "content" in msg:
with st.chat_message("user", avatar='😀'):
st.write(msg["content"])
elif "image" in msg:
if msg["image"]:
st.image(msg["image"], caption="Uploaded Image", width=400)
elif msg["role"] == "assistant":
st.chat_message("assistant", avatar='🤖').write(msg["content"])
# -----------------------------------------------------
# チャットボットのメイン処理
# -----------------------------------------------------
# ユーザーからの入力
user_input = st.chat_input("メッセージを入力してください:")
if user_input:
st.session_state.messages.append({"role": "user", "content": user_input})
st.chat_message("user", avatar="😎").write(user_input)
with st.spinner("Difyと通信中..."):
response = send_message_to_dify(
user_message=user_input,
conversation_id=st.session_state.conversation_id,
user_id=user_id,
)
# conversation_idの更新
st.session_state.conversation_id = response.get('conversation_id', st.session_state.conversation_id)
answer = response.get('answer', '')
# ボットの回答を表示
st.session_state.messages.append({"role": "assistant", "content": answer})
st.chat_message("assistant", avatar="🎅").write(answer)
# -----------------------------------------------------
# 画像のアップロード
# -----------------------------------------------------
with st.sidebar.expander("画像のアップロード", expanded=False):
upload_image = st.file_uploader("画像をアップロード", type=["png", "jpg", "jpeg"], accept_multiple_files=False)
# Difyに画像を渡して、画像IDを取得
if upload_image:
st.image(upload_image, caption=f"{upload_image.name}", width=200)
if st.button("**画像をアップロード!**"):
# ファイルIDを取得
st.session_state.file_id = upload_image_to_dify(upload_image, user_id)
if st.session_state.file_id == "":
st.warning("画像のアップロードに失敗しました。")
st.stop()
st.write(f'file_id: {st.session_state.file_id}')
# 画像を説明してもらう
if st.session_state.file_id != "":
user_input = "何が写っているか説明してください。"
response = send_message_to_dify(
user_message=user_input,
conversation_id=st.session_state.conversation_id,
user_id=user_id,
file_id=st.session_state.file_id
)
# conversation_idの更新
st.session_state.conversation_id = response.get('conversation_id', st.session_state.conversation_id)
# 質問、画像、回答をmessages_difyに格納
st.session_state.messages.append({"role": "user", "content": user_input})
st.session_state.messages.append({"role": "user", "image": upload_image})
answer = response.get('answer', '')
st.session_state.messages.append({"role": "assistant", "content": answer})
st.rerun()
# -----------------------------------------------------
# 会話履歴の管理
# -----------------------------------------------------
with st.sidebar.expander("過去会話の管理", expanded=False):
# -----------------------------------------------------
# ユーザーIDに紐づく会話リストを取得、再取得
# -----------------------------------------------------
st.write("1_過去会話リストを読み込む")
if 'conversations' not in st.session_state:
st.session_state.conversations = dify_get_conversations(user_id=user_id)
if st.button("リストの再取得"):
st.session_state.conversations = dify_get_conversations(user_id=user_id)
# key: 会話名, value: 会話ID の辞書を作成
conversations_dict = {item['name']: item['id'] for item in st.session_state.conversations}
# -----------------------------------------------------
# 過去会話のロード
# -----------------------------------------------------
if not conversations_dict:
st.stop()
st.write("2_過去会話を読み込む")
conversation_name = st.selectbox("過去会話を選択", list(conversations_dict.keys()))
if st.button("👆これを読込む") and conversations_dict:
# 現在の会話を削除
del st.session_state.messages
# 会話履歴を取得
raw_messages = dify_get_messages(user_id=user_id, conversation_id=conversations_dict[conversation_name])
# 会話IDを更新
st.session_state.conversation_id = conversations_dict[conversation_name]
# 会話履歴をst.session_state.messagesに格納
st.session_state.messages = []
for msg in raw_messages:
if msg['query']: # userメッセージはこのキーで格納されている
st.session_state.messages.append({"role": "user", "content": msg['query']})
if msg['answer']: # assistantメッセージはこのキーで格納されている
st.session_state.messages.append({"role": "assistant", "content": msg['answer']})
st.rerun()
# -----------------------------------------------------
# 会話名の変更
# -----------------------------------------------------
st.write("3_会話名を変更")
new_conversation_name = st.text_input("新しい会話名を入力", value=conversation_name)
if st.button("👆これに名称変更"):
dify_rename_conversation(user_id, conversations_dict[conversation_name], new_conversation_name)
# -----------------------------------------------------
# 会話の削除
# -----------------------------------------------------
st.write("4_選択中の会話を削除")
if st.button("選択中の会話を削除"):
dify_delete_conversation(user_id, conversations_dict[conversation_name])
if __name__ == "__main__":
dify_chatbot()
- streamlitアプリを起動
streamlit run main.py

ワークフローアプリAPIをまとめる
ゴール
- APIアクセスページのサンプルcurlコマンドをPythonコードにしてめとめる
まとめ
- できることは以下のとおり
- ワークフローを実行
- ワークフロー実行詳細を取得
- 生成を停止
- ファイルをアップロード
- ワークフォローログを取得
- アプリ基本情報を取得
- アプリのパラメータ情報を取得
参考リンク
- チャットアプリAPIをまとめる ※少し前の投稿です
- 公式Doc>ワークフロー
手順
- Difyでワークフローを作る
- APIアクセスページでAPIサーバURLをコピー
- APIキーを作成してコピー
- 以下のサンプルコードを使いこなす!
APIサンプルコード
import requests
import json
# グローバル設定
API_KEY = "app-xxxxxxxx" # アプリ毎に異なるAPIキー
BASE_URL = "http://161.93.+++.+++:++++/v1" # DifyのベースURL
HEADERS = {
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json"
}
# 1. ワークフロー実行
def run_workflow(file_id, user, response_mode="blocking"):
url = f"{BASE_URL}/workflows/run"
data = {
"inputs": {
"orig_mail": {
"transfer_method": "local_file",
"upload_file_id": file_id,
"type": "document"
}
},
"response_mode": response_mode,
"user": user
}
try:
print("ワークフローを実行しています...")
response = requests.post(url, headers=HEADERS, json=data)
if response.status_code == 200:
print("ワークフローが正常に実行されました")
return response.json()
else:
print(f"ワークフロー実行が失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
# 2. ワークフロー詳細取得
def get_workflow_details(workflow_id):
url = f"{BASE_URL}/workflows/run/{workflow_id}"
try:
print("ワークフロー詳細を取得しています...")
response = requests.get(url, headers=HEADERS)
if response.status_code == 200:
print("ワークフロー詳細が取得されました")
return response.json()
else:
print(f"ワークフロー詳細取得が失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
# 3. 生成を停止
def stop_workflow(task_id, user):
url = f"{BASE_URL}/workflows/tasks/{task_id}/stop"
data = {"user": user}
try:
print("ワークフローの生成を停止しています...")
response = requests.post(url, headers=HEADERS, json=data)
if response.status_code == 200:
print("ワークフローの生成が停止されました")
return response.json()
else:
print(f"ワークフロー生成停止が失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
# 4. ファイルアップロード
def upload_file(file_path, user):
url = f"{BASE_URL}/files/upload"
try:
print("ファイルをアップロードしています...")
with open(file_path, 'rb') as file:
files = {
'file': (file_path, file, 'text/plain')
}
data = {
"user": user,
"type": "TXT"
}
response = requests.post(url, headers={"Authorization": f"Bearer {API_KEY}"}, files=files, data=data)
if response.status_code == 201:
print("ファイルが正常にアップロードされました")
return response.json().get("id")
else:
print(f"ファイルアップロードが失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
# 5. ワークフローログ取得
def get_workflow_logs(user, limit=10):
url = f"{BASE_URL}/workflows/logs"
params = {
"user": user,
"limit": limit
}
try:
print("ワークフローログを取得しています...")
response = requests.get(url, headers=HEADERS, params=params)
if response.status_code == 200:
print("ワークフローログが取得されました")
return response.json()
else:
print(f"ワークフローログ取得が失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
# 6. アプリ基本情報取得
def get_app_info(user):
url = f"{BASE_URL}/info"
params = {"user": user}
try:
print("アプリ基本情報を取得しています...")
response = requests.get(url, headers=HEADERS, params=params)
if response.status_code == 200:
print("アプリ基本情報が取得されました")
return response.json()
else:
print(f"アプリ基本情報取得が失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
# 7. アプリパラメータ情報取得
def get_app_parameters(user):
url = f"{BASE_URL}/parameters"
params = {"user": user}
try:
print("アプリパラメータ情報を取得しています...")
response = requests.get(url, headers=HEADERS, params=params)
if response.status_code == 200:
print("アプリパラメータ情報が取得されました")
return response.json()
else:
print(f"アプリパラメータ情報取得が失敗しました。ステータスコード: {response.status_code}")
return {"status": "error", "message": response.text}
except Exception as e:
print(f"エラーが発生しました: {str(e)}")
return {"status": "error", "message": str(e)}
if __name__ == "__main__":
user = "difyuser"
file_path = "path/to/file.txt"
# 1. ファイルアップロード
print("=== ファイルアップロード ===")
file_id = upload_file(file_path, user)
print("アップロード結果:", file_id)
if file_id:
# 2. ワークフロー実行
print("\n=== ワークフロー実行 ===")
workflow_result = run_workflow(file_id, user)
print("ワークフロー実行結果:", workflow_result)
# ワークフローIDとタスクIDの取得(仮にJSONのキー名が `workflow_run_id` と `task_id` とする)
workflow_id = workflow_result.get("workflow_run_id")
task_id = workflow_result.get("task_id")
# 3. ワークフロー詳細取得
if workflow_id:
print("\n=== ワークフロー詳細取得 ===")
workflow_details = get_workflow_details(workflow_id)
print("ワークフロー詳細:", workflow_details)
# 4. ワークフローの生成停止
if task_id:
print("\n=== ワークフローの生成停止 ===")
stop_result = stop_workflow(task_id, user)
print("生成停止結果:", stop_result)
# 5. ワークフローログ取得
print("\n=== ワークフローログ取得 ===")
logs = get_workflow_logs(user, limit=10)
print("ワークフローログ:", logs)
# 6. アプリ基本情報取得
print("\n=== アプリ基本情報取得 ===")
app_info = get_app_info(user)
print("アプリ基本情報:", app_info)
# 7. アプリパラメータ情報取得
print("\n=== アプリパラメータ情報取得 ===")
app_parameters = get_app_parameters(user)
print("アプリパラメータ情報:", app_parameters)

Dify v1.4.0をセルフホストする
※ 2025-07-09追記あり
ゴール
- Windows + wsl2 + docker + DockerDesktop + proxyあり の環境で、dify v1の最新バージョンである dify v1.4.0 をセルフホストする(注意:v0環境からのアップデートではない)
まとめ
- 起動はできるがツールをインストールしようとすると発生するエラー(internal error)の解消にてこずったが、ChatGPT(o3)のお陰で無事動かせるようになった
- 2025-07-09追記:
docker-compose.yaml
のapiサービスにports設定を追加。これがないとファイルアップロードが機能しなかった。
参考リンク
手順
- 事前準備(ここに少し書いてある)
- gitインストール
- wsl2有効化
- Docker Desktop for Windowsインストール
- proxyサーバの設定も忘れずに
- 最新バージョンを公式リポジトリからダウンロード
git clone https://github.com/langgenius/dify.git
- dify>dockerフォルダの
docker-compose.yaml
と.env
ファイルを一部変更する(後述)(.env
ファイルはenv.sample
からファイル名を変更する) - あとは起動!
docker compose up -d
- 成功!
docker-compose.yaml変更箇所
### 変更箇所5(2025-07-09追記) ###
services:
# API service
api:
ports: ##追加 2025-07-08
- "5001:5001" ##追加 2025-07-08
### 変更箇所1,2 ###
# The postgres database.
db:
volumes:
## 変更前
# - ./volumes/db/data:/var/lib/postgresql/data
## 変更後
- postgres_data:/var/lib/postgresql/data
healthcheck:
test: [ 'CMD', 'pg_isready', '-h', 'db', '-U', '${PGUSER:-postgres}', '-d', '${POSTGRES_DB:-dify}' ]
interval: 1s
timeout: 3s
retries: 60
## 追加
ports:
- "5432:5432"
### 変更箇所3 ###
# plugin daemon
plugin_daemon:
volumes:
## 変更前
# - ./volumes/plugin_daemon:/app/storage
## 変更後
- plugin_daemon_data:/app/storage
depends_on:
db:
condition: service_healthy
### 変更箇所4 ###
volumes:
oradata:
dify_es01_data:
## 2行追加
postgres_data:
plugin_daemon_data:
.env変更箇所
### 変更箇所1 ###
## オリジナルは空欄、ホストPCの固定IP、ポートは任意
CONSOLE_API_URL=http://161.93.+++.+++:8880
CONSOLE_WEB_URL=http://161.93.+++.+++:8880
SERVICE_API_URL=http://161.93.+++.+++:8880
APP_API_URL=http://161.93.+++.+++:8880
APP_WEB_URL=http://161.93.+++.+++:8880
FILES_URL=http://161.93.+++.+++:5001
### 変更箇所2 ###
# INIT_PASSWORD=
INIT_PASSWORD=passpass
### 変更箇所3 ###
# SERVER_WORKER_AMOUNT=1
SERVER_WORKER_AMOUNT=4
### 変更箇所4 ###
# CELERY_WORKER_AMOUNT=
CELERY_WORKER_AMOUNT=2
### 変更箇所5 ###
# POSTGRES_SHARED_BUFFERS=128MB
POSTGRES_SHARED_BUFFERS=512MB
### 変更箇所6 ###
# EXPOSE_NGINX_PORT=80
# EXPOSE_NGINX_SSL_PORT=443
EXPOSE_NGINX_PORT=8880
EXPOSE_NGINX_SSL_PORT=8443
### 変更箇所7 ###
# EXPOSE_PLUGIN_DEBUGGING_HOST=localhost
EXPOSE_PLUGIN_DEBUGGING_HOST=plugin_daemon
EXPOSE_PLUGIN_DEBUGGING_PORT=5003
### 変更箇所8 ###
# FORCE_VERIFYING_SIGNATURE=true
FORCE_VERIFYING_SIGNATURE=false
### 変更箇所9 ###
# PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=320
### 変更箇所10 ###
# PLUGIN_PYTHON_ENV_INIT_TIMEOUT=120
PLUGIN_PYTHON_ENV_INIT_TIMEOUT=320
### 変更箇所11 ###
# The maximum number of top-k value for RAG.
TOP_K_MAX_VALUE=50
docker-compose.yamlの変更点と理由まとめ
箇所 | 変更内容 | なぜ必要だったか |
---|---|---|
db.volumes |
./volumes/db/data → named-volume postgres_data
|
既存バインドマウントに壊れた WAL やロックが残りコンテナを再作成しても復活してしまうため。匿名ではなく名前付き volume に切替え、docker volume rm で完全にリセットできるようにした。 |
db.ports |
5432:5432 を追加 |
ホスト OS から直接 psql / BI ツールで接続・デバッグできるようにポートを公開。 |
plugin_daemon.volumes |
./volumes/plugin_daemon → named-volume plugin_daemon_data
|
plugin ディレクトリと仮想環境が壊れた時に docker volume rm plugin_daemon_data で丸ごと初期化できるようにするため。 |
volumes: |
postgres_data / plugin_daemon_data を追加 |
上記 named-volume 用の定義。 |
api.environment |
PLUGIN_REMOTE_INSTALL_HOST/PORT を env 展開に変更 |
API が plugin-daemon 実ホスト名 を解決できるよう、.env 側の値をそのまま参照する形に統一。 |
(参考) plugin_daemon.ports
|
"${EXPOSE_PLUGIN_DEBUGGING_PORT}:5003" |
デバッグ用 gRPC 5003 を外に出すことでローカル開発時に grpcurl 等で疎通確認が可能。 |
.envの変更点と理由まとめ
箇所 | 変更内容 | なぜ必要だったか |
---|---|---|
CONSOLE_API_URL など4つ |
http://<IP>:8880 を設定 | Nginx を 8880 で公開したため、フロント/SDK が正しい URL を組み立てられるようにする。 |
INIT_PASSWORD |
(コメントアウト行)# INIT_PASSWORD= → INIT_PASSWORD=passpass
|
初回セットアップ時に管理者アカウントを作成する際、コンソールで毎回パスワード入力を求められず自動化できる。CI/CD や再デプロイ時の手間を削減。 |
FILES_URL |
http://<IP>:5001 | マルチモーダル入力やファイル出力で生成される署名付き URL のホスト名を固定。 |
SERVER_WORKER_AMOUNT |
1 → 4 | Gunicorn worker を CPU コア数 x2+1 目安へ増量し、同時 API リクエスト処理性能を向上。 |
CELERY_WORKER_AMOUNT |
空 → 2 | 非同期タスク(RAG 取り込み・画像処理など)が詰まりにくいように増員。 |
POSTGRES_SHARED_BUFFERS |
128MB → 512MB | VM のメモリに余裕があるため PostgreSQL のキャッシュを 4 倍にし、I/O を低減。 |
EXPOSE_NGINX_PORT/SSL_PORT |
8880 / 8443 | 80/443 を別サービスで使っている環境のためポートをずらした。compose 側の publish とペア。 |
EXPOSE_PLUGIN_DEBUGGING_HOST |
localhost → plugin_daemon
|
決定打。API が gRPC でプラグインを検証するとき localhost:5003 に繋ぎに行く → コンテナ内からは通らず “no available node” エラー。Docker DNS 解決可能な plugin_daemon:5003 に修正して解消。 |
FORCE_VERIFYING_SIGNATURE |
true → false | 社内/ローカルでビルドしたプラグインに署名が無いとインストールできないため、検証をスキップ。 |
PLUGIN_PYTHON_ENV_INIT_TIMEOUT |
120 → 320 | Azure SDK など重量級プラグインの pip install が 2 分を超えることがあり、タイムアウトを延長。 |
(補足) SERVER_WORKER_AMOUNT , CELERY_WORKER_AMOUNT , POSTGRES_*
|
リソース・パフォーマンス調整 | いずれも「CPU/RAM 余裕があるなら増やすと快適」系のチューニング。 |
TOP_K_MAX_VALUE |
10⇒50 | 知識検索ブロックで取得するチャンク数を増やす |
設定変更&エラー解消方法まとめ
全体として解決できたこと
- プラグイン検証エラー (no available node) の根本原因
- API → plugin-daemon 間の gRPC 経路を plugin_daemon:5003 に正しく向けたことで解消。
- ゴミが残る/再インストールで壊れる問題の解消
- DB と plugin-daemon のストレージを named-volume 化し、docker compose down -v で完全クリアできるようにした。
- 性能改善 & 外部アクセス性向上
- worker 数・PostgreSQL バッファ・公開ポートなどを実行環境に合わせて最適化。

Difyを自己署名証明書でhttps化する
ゴール
- httpsホストして、音声入力をできるようにする。
まとめ
- https化はできたが、whisperは言語指定ができず、日本語で話しかけても英語で文字起こししてしまうことが分かった。。(GitHubリポジトリ Isssue)。
参考リンク
手順
1. 自己署名証明書の作成
以下のコマンドを Git Bash で実行します。
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout server.key -out server.crt
- 各入力項目は空EnterでOK。
-
Common Name
には サーバIP(例:161.93.+++.+++) を入れるとベター。 -
server.key
とserver.crt
が生成されます。
.env
ファイルの編集(http → https)
2. 変更前:
CONSOLE_API_URL=http://161.93.+++.+++:8880
CONSOLE_WEB_URL=http://161.93.+++.+++:8880
SERVICE_API_URL=http://161.93.+++.+++:8880
APP_API_URL=http://161.93.+++.+++:8880
APP_WEB_URL=http://161.93.+++.+++:8880
NGINX_HTTPS_ENABLED=false
変更後:
CONSOLE_API_URL=https://161.93.+++.+++:8443
CONSOLE_WEB_URL=https://161.93.+++.+++:8443
SERVICE_API_URL=https://161.93.+++.+++:8443
APP_API_URL=https://161.93.+++.+++:8443
APP_WEB_URL=https://161.93.+++.+++:8443
NGINX_HTTPS_ENABLED=true
補足:
-
8443
を使う理由は、EXPOSE_NGINX_SSL_PORT=8443
とポートを合わせているため。 - Entra ID 連携や外部連携も
:8443
を指定。 - HTTP(8880)は
EXPOSE_NGINX_PORT=8880
のままでもOK。 -
FILES_URL
(ファイルアップロード用)は HTTPのままにしておく。
3. 証明書ファイルの設置
-
ファイル名を変更:
-
server.crt
→dify.crt
-
server.key
→dify.key
-
-
設置先:
C:\dify-v1\docker\nginx\ssl
または docker-compose.yaml
でマウントされているSSLディレクトリに配置。
-
.env
に以下を追加しておくと確実:
NGINX_SSL_CERT_FILENAME=dify.crt
NGINX_SSL_CERT_KEY_FILENAME=dify.key
4. Dify コンテナの停止
docker compose -p dify-v1 down
5. Dify コンテナの再起動(HTTPS化適用)
docker compose -p dify-v1 up -d
補足:
-
.env
と証明書内容が反映されて自動で再構築。 -
ポート
8443
でhttps://161.93.+++.+++:8443
にアクセスできればOK。 -
初回は「安全ではありません」と警告されますが、証明書例外登録で利用可能。
-
証明書更新時も同じディレクトリに上書きして再起動すればOK。
-
社外公開や本番用途 は Let’s Encrypt証明書+自動更新を推奨。
-
8443
以外のカスタムポートを使う場合は、すべてのURLにポート番号を明記。