自宅PCのAPIサーバを公開して、Difyの外部ナレッジAPIとして活用する手順です。
<Difyで使うかどうかに関わらず、Webサーバを公開する際に便利です>
https://www.creationline.com/tech-blog/cloudnative/75142
上記の記事を参考にして作業しました。
<terraformが出てきたところから分からなかったので、Chatgptに聞きながら作業しました>
以下Chatgptとの対話です。
質問 <ここは概要を理解するための質問なので、この通り実施しない>
Cloudflare Tunnel: をWINDOWSで使う手順を詳細に教えて
Cloudflare TunnelをWindowsで使用する手順を説明します:
1.Cloudflaredのインストール:
Cloudflareのダウンロードページ から Windows用の実行ファイルをダウンロード
ダウンロードしたexeファイルを実行してインストール
2.Cloudflareアカウントの設定:
PowerShellを管理者として実行し、以下のコマンドを実行
cloudflared.exe login
ブラウザが開き、Cloudflareにログインするように促される
ログイン後、認証証明書が自動的に保存される
(通常は C:\Users<ユーザー名>.cloudflared\cert.pem)
3.トンネルの作成:
トンネルの作成
cloudflared.exe tunnel create rag-api
トンネルのIDを確認(後で使用)
cloudflared.exe tunnel list
4.設定ファイルの作成:
C:\Users<ユーザー名>.cloudflared\config.yml を作成:
tunnel: <トンネルID>
credentials-file: C:\Users\<ユーザー名>\.cloudflared\<トンネルID>.json
ingress:
- hostname: your-domain.com
service: http://localhost:8000
- service: http_status:404
5.DNSレコードの設定:
DNSレコードを作成
cloudflared.exe tunnel route dns rag-api yourdomain.com
6.トンネルの実行:
トンネルを起動
cloudflared.exe tunnel run rag-api
7.Windowsサービスとして実行(オプション):
サービスとしてインストール
cloudflared.exe service install
サービスを開始
Start-Service cloudflared
8.動作確認:
テストAPIの実行
curl -X POST https://rag-api.yourdomain.com/retrieval \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_API_KEY" \
-d '{
"knowledge_id": "test-knowledge",
"query": "RAGについて教えて",
"retrieval_setting": {
"top_k": 3,
"score_threshold": 0.5
}
}'
セキュリティ上の注意点:
config.yml のパーミッションを適切に設定
証明書ファイル(cert.pem)を安全に保管
APIキーを環境変数として設定
ファイアウォールの設定を確認
トラブルシューティング:ログは C:\Users<ユーザー名>.cloudflared\ に保存される
エラーが発生した場合は
cloudflared.exe tunnel info rag-api で状態を確認
必要に応じて --loglevel debug オプションを使用
次のステップ:
1.トンネルの作成:
cloudflared.exe tunnel create rag-api-tunnel
2.設定ファイルの作成(C:\Users<ユーザー名>.cloudflared\config.yml):
tunnel: 3196188c3762a6aef47dd852d124
credentials-file: C:\Users\<ユーザー名>\.cloudflared\3196188c3762a6aef47dd852d124.json
ingress:
- hostname: your-domain.cloudflare.com
service: http://localhost:8000
- service: http_status:404
3.トンネルの起動:
cloudflared.exe tunnel run rag-api-tunnel
<ここまでは概要を理解するための質問なので、この通り実施しない>
質問 windows11 で、Cloudflare を活用して、現在作成中のmain.pyを公開したら、Difyの外部ナレッジとして活用できるよね?
はい、その通りです。現在のコードをCloudflare Tunnelで公開するための手順を説明します:
1.必要な追加パッケージ:
scikit-learn
numpy
pandas
flask
python-dotenv
mecab-python3
unidic-lite
gunicorn # 本番環境用のWSGIサーバー
2.config.py の作成 (まだない場合):
import os
from dotenv import load_dotenv
load_dotenv()
# APIキー設定
API_KEY = os.getenv("API_KEY", "your_API_KEY")
# RAG設定
DEFAULT_TOP_K = 3
DEFAULT_SCORE_THRESHOLD = 0.5
CSV_PATH = "RAG.csv"
# サーバー設定
HOST = "0.0.0.0"
PORT = int(os.getenv("PORT", 8000))
3.Cloudflare Tunnelのセットアップ手順:
3-1. cloudflaredをインストール
https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/
から最新のWindows用インストーラーをダウンロード
3-2. Cloudflareにログイン
cloudflared-windows-amd64.exe login
3-3. トンネルを作成
cloudflared-windows-amd64.exe tunnel create rag-api
3-4. トンネルのIDをメモ
cloudflared-windows-amd64.exe tunnel list
4.設定ファイルの作成 (C:\Users<ユーザー名>.cloudflared\config.yml):
tunnel: <トンネルID>
credentials-file: C:\Users\<ユーザー名>\.cloudflared\<トンネルID>.json
ingress:
- hostname: rag-api.yourdomain.com
service: http://localhost:8000
- service: http_status:404
# オプションの設定
originRequest:
connectTimeout: 30s
noTLSVerify: true
5.DNSレコードの設定:
cloudflared.exe tunnel route dns rag-api rag-api.yourdomain.com
6.トンネルの起動:
cloudflared.exe tunnel run rag-api
これで、Difyの外部ナレッジ設定で以下のように設定できます:
URL: https://rag-api.yourdomain.com/retrieval
Method: POST
Headers:
Authorization: Bearer your_API_KEY
Content-Type: application/json
注意点:
1.MeCabのパスが環境に依存しているので、以下のように修正することをお勧めします:
import pandas as pd
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
import logging
import MeCab
import re
import traceback
import os
class RAGEngine:
def __init__(self, csv_path):
self.df = pd.read_csv(csv_path, encoding='utf-8')
# MeCabのパスを環境変数から取得するか、デフォルトパスを使用
mecab_path = os.getenv('MECAB_PATH', '-Owakati')
self.mecab = MeCab.Tagger(mecab_path)
# 初期化時のエラーを回避するためのダミー解析
self.mecab.parse('')
self.vectorizer = TfidfVectorizer(
analyzer='char_wb',
ngram_range=(2, 3),
max_features=10000,
min_df=1,
max_df=0.95,
sublinear_tf=True,
token_pattern=r'(?u)\b\w+\b' # 単語の境界をより厳密に
)
self._prepare_vectors()
def tokenize(self, text):
"""テキストを形態素解析して単語に分割"""
try:
text = self.preprocess_text(text)
result = self.mecab.parse(text)
if result is None:
logging.error("MeCab parse returned None")
return []
tokens = result.strip().split()
logging.debug(f"Tokenized text: {tokens}") # デバッグ用ログ
return tokens
except Exception as e:
logging.error(f"Tokenization error for text '{text}': {str(e)}")
return []
def preprocess_text(self, text):
"""テキストの前処理"""
if not isinstance(text, str):
text = str(text)
# 改行を空白に置換
text = re.sub(r'\n', ' ', text)
# 特殊文字を削除
text = re.sub(r'[【】「」『』()\[\]()\(\)]+', ' ', text)
# 連続する空白を1つに置換
text = re.sub(r'\s+', ' ', text)
return text.strip()
def _prepare_vectors(self):
"""質問のベクトル化を行う"""
try:
# 質問テキストを抽出してベクトル化
questions = self.df['question'].fillna('')
# 前処理を適用
processed_questions = [self.preprocess_text(q) for q in questions]
self.question_vectors = self.vectorizer.fit_transform(processed_questions)
# デバッグ用ログ
logging.info("Vectors prepared successfully")
logging.debug(f"Total questions: {len(processed_questions)}")
for i, (orig, proc) in enumerate(zip(questions, processed_questions)):
logging.debug(f"Q{i}: Original: {orig}")
logging.debug(f"Q{i}: Processed: {proc}")
except Exception as e:
logging.error(f"Error preparing vectors: {str(e)}")
raise
def search(self, query, top_k=5, score_threshold=0.5):
"""クエリに類似した質問-回答ペアを検索する"""
try:
# ク���リの前処理
processed_query = self.preprocess_text(query)
logging.debug(f"Search query: {query} -> {processed_query}")
# クエリをベクトル化
query_vector = self.vectorizer.transform([processed_query])
# コサイン類似度を計算
similarities = cosine_similarity(query_vector, self.question_vectors).flatten()
# クエリの意図を分析
query_keywords = {
'RAG': ['rag', 'retrieval', 'augmented', 'generation'],
'Dify': ['dify', 'defy', 'platform', 'プラットフォーム'],
# 他のトピックも必要に応じて追加
}
# クエリがどのトピックに関連するか判定
query_lower = query.lower()
matched_topic = None
for topic, keywords in query_keywords.items():
if any(keyword in query_lower for keyword in keywords):
matched_topic = topic
break
if matched_topic:
# トピックに関連する問のスコアを調整
for i, question in enumerate(self.df['question']):
question_lower = question.lower()
if any(keyword in question_lower for keyword in query_keywords[matched_topic]):
similarities[i] *= 2.0 # 関トピックのスコアを増加
else:
similarities[i] *= 0.5 # 無係なトピックのスコアを減少
# スコアの正規化(0-1の範囲に)
max_score = similarities.max()
if max_score > 0:
similarities = similarities / max_score
# 上位k件を取得
top_indices = np.argsort(similarities)[-top_k:][::-1]
results = []
for idx in top_indices:
score = float(similarities[idx])
if score >= score_threshold: # スコアが閾値以上の結果のみを返す
row = self.df.iloc[idx]
result = {
"content": str(row['Answer']),
"score": score,
"title": row['Title'],
"metadata": {}
}
if 'url' in row:
result["metadata"]["url"] = row['url']
results.append(result)
logging.info(f"Found match: {row['question']} (score: {score:.4f})")
return results
except Exception as e:
logging.error(f"Search error: {str(e)}\n{traceback.format_exc()}")
raise
2.セキュリティ強化のために、API_KEYを環境変数から取得するようにしましょう。
これらの設定が完了すれば、DifyからRAG APIとして利用できるようになります。
質問 WEB画面でDNSレコードを修正するなどの作業は必要ないですか?
Cloudflareのウェブ画面での設定も必要です。以下の手順で設定を行います:
1.Cloudflareのダッシュボードにログイン:
https://dash.cloudflare.com にアクセス
2.ドメインの設定:
使用するドメインを選択(または新規追加)
「DNS」タブを選択
3.DNSレコードの追加:
「レコードを追加」をクリック
以下の設定を入力:
Type: CNAME
Name: rag-api(サブドメイン名)
Target: your-tunnel-id.cfargotunnel.com
Proxy status: Proxied(オレンジの雲マーク)
4.SSL/TLS設定:
「SSL/TLS」タブを選択
暗号化モード: 「Full」または「Full (Strict)」を選択
5.ゼロトラストの設定(オプション):
「Zero Trust」→「Access」→「Applications」
「Add an application」をクリック
アプリケーション名とドメインを設定
必要に応じてアクセス制御を設定
6.トンネルの確認:
トンネルの状態確認
cloudflared.exe tunnel info rag-api
DNSレコードの確認
cloudflared.exe tunnel route dns rag-api rag-api.yourdomain.com
これらの設定が完了したら、以下のURLでAPIにアクセスできるようになります:
https://rag-api.yourdomain.com/retrieval
Difyの外部ナレッジ設定では、このURLを使用します。
注意点:DNSの反映には数分から数時間かかる場合があります
SSL証明書の生成と適用も自動的に行われますが、少し時間がかかります
初回アクセス時にCloudflareの保護機能による確認が入る場合があります
質問 これは、トンネルIDですか?
.\cloudflared-windows-amd64.exe tunnel create rag-api
Tunnel credentials written to C:\Users\tarou\.cloudflared\e773085c-a587-4c1a-b7f7.json. cloudflared chose this file based on where your origin certificate was found. Keep this file secret. To revoke these credentials, delete the tunnel.
Created tunnel rag-api with id e773085c-a587-4c1a-b7f7
はい、その通りです。トンネルIDは: e773085c-a587-4c1a-b7f7 です。
このIDを使って、C:\Users\tarou.cloudflared\config.yml を以下のように作成します:
tunnel: e773085c-a587-4c1a-b7f7
credentials-file: C:\Users\tarou\.cloudflared\e773085c-a587-4c1a-b7f7.json
ingress:
- hostname: rag-api.your-domain.com
service: http://localhost:8000
- service: http_status:404
#オプションの設定
originRequest:
connectTimeout: 30s
noTLSVerify: true
このトンネルIDは、以下のような操作でも確認できます:
.\cloudflared-windows-amd64.exe tunnel list
このIDは重要な情報なので、安全に保管してください。トンネルを削除する必要がある場合は、このIDを使用します。
質問 DNSレコードの設定はOK?
.\cloudflared-windows-amd64.exe tunnel route dns rag-api rag-api.yourdomain.com
2024-12-08T10:39:18Z INF Added CNAME rag-api.yourdomain.com which will route to this tunnel tunnelID=e773085c-a587-4c1a-b7f7
PS C:\Users\tarou\DifyAPI>
はい、DNSレコードの設定は正常に完了しています。メッセージの内容から:
1.CNAMEレコードが正常に追加されました
2.ホスト名: rag-api.yourdomain.com
3.トンネルID: e773085c-a587-4c1a-b7f7
次のステップとして、config.yml を以下のように更新する必要があります:
tunnel: e773085c-a587-4c1a-b7f7
credentials-file: C:\Users\tarou\.cloudflared\e773085c-a587-4c1a-b7f7.json
ingress:
- hostname: rag-api.yourdomain.com
service: http://localhost:8000
- service: http_status:404
originRequest:
connectTimeout: 30s
noTLSVerify: true
これで、以下のURLでAPIにアクセスできるようになります:
https://rag-api.yourdomain.com/retrieval
トンネルを起動するには:
.\cloudflared-windows-amd64.exe tunnel run rag-api
質問
- self.mecab = MeCab.Tagger('-Owakati -r "C:/Program Files/MeCab/etc/mecabrc"')
を削除して、
mecab_path = os.getenv('MECAB_PATH', '-Owakati')
self.mecab = MeCab.Tagger(mecab_path)
を追加するということは、環境変数に
MECAB_PATH=”C:/Program Files/MeCab/etc/mecabrc”
と記述が必要ですね?
はい、その通りです。.env ファイルに以下のように環境変数を設定する必要があります:
# MeCab設定
MECAB_PATH=-Owakati -r "C:/Program Files/MeCab/etc/mecabrc"
# APIキー設定
API_KEY=your_API_KEY
# サーバー設定
PORT=8000
この設定により:rag.py で os.getenv('MECAB_PATH', '-Owakati') を使用したとき、
.env ファイルから設定を読み込みます
環境変数 MECAB_PATH が設定されていない場合は、デフォルト値 -Owakati が使用されます
Windows環境でのMeCabの設定が正しく維持されます
注意点:パスに空白が含まれているため、ダブルクォート " で囲む必要があります
パスの区切り文字はフォワードスラッシュ / を使用します
次のステップ:
1.トンネルを起動:
.\cloudflared-windows-amd64.exe tunnel run rag-api
2.動作確認:
curl -X POST https://rag-api.yourdomain.com/retrieval \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your_API_KEY" \
-d '{
"knowledge_id": "test-knowledge",
"query": "RAGについて教えて",
"retrieval_setting": {
"top_k": 3,
"score_threshold": 0.5
}
}'
この状態で、Difyの外部ナレッジベース設定で以下のように設定できます:
URL: https://rag-api.yourdomain.com/retrieval
Method: POST
Headers:
- Content-Type: application/json
- Authorization: Bearer your_API_KEY
Request Body Format:
{
"knowledge_id": "test-knowledge",
"query": "${input}",
"retrieval_setting": {
"top_k": 3,
"score_threshold": 0.5
}
}
質問 difyの外部ナレッジベースへの接続画面があります。
以下の2か所を設定をする必要があります。
何を入れれば良い?
1)外部ナレッジ名(ナレッジベースの名前を入力してください)
2)外部ナレッジID(ナレッジIDを入力してください)
外部ナレッジAPIには、「rag-api」と入力されてます
Difyの外部ナレッジベース設定では、以下のように入力することをお勧めします:
1.外部ナレッジ名:
RAG Knowledge Base
または
RAG API Knowledge Base
2.外部ナレッジID
test-knowledge
理由:外部ナレッジIDは、APIリクエストの knowledge_id パラメータと一致する必要があります
現在のAPIコードでは test-knowledge を使用しています(curlコマンドのテストで使用した値)
注意:外部ナレッジ名は管理用の表示名なので、分かりやすい名前を付けることができます
外部ナレッジIDは、APIリクエストで使用される識別子なので、コードと一致させる必要があります
以上