Spaces:
Sleeping
Sleeping
File size: 6,886 Bytes
fc5d3b5 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | import gradio as gr
import cohere
import psycopg2
from psycopg2.extras import RealDictCursor
from datetime import datetime
from dotenv import load_dotenv
import os
load_dotenv(verbose=True)
# --- 設定 ---
COHERE_API_KEY = os.getenv("COHERE_API_KEY")
DB_CONFIG = {
"host": "www.ryhintl.com",
"dbname": "smair",
"user": "smairuser",
"password": "smairuser",
"port": 10629,
"connect_timeout": 15
}
co = cohere.Client(COHERE_API_KEY)
# --- 登録関数 ---
def register_trouble(date, process, equipment, title, phenomenon, cause, action, prevention, severity):
if not title or not phenomenon:
return "⚠️ タイトルと現象は必須入力項目です。"
conn = None
try:
# 1. 登録用テキストを結合してベクトル化 (Embedding生成)
# 検索精度を高めるため、主要な情報をすべて含める
input_text = f"【{process}】{title} 現象:{phenomenon} 原因:{cause} 処置:{action} 防止策:{prevention}"
res = co.embed(
texts=[input_text],
model='embed-multilingual-v3.0',
input_type='search_document' # 登録時は document を指定
)
embedding = res.embeddings[0]
# 2. DB接続とインサート
conn = psycopg2.connect(**DB_CONFIG, client_encoding='utf8')
cur = conn.cursor()
insert_query = """
INSERT INTO public.factory_troubles (
occurrence_date, process_name, equipment_name, title,
phenomenon, cause, action, prevention, severity, embedding
) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
"""
cur.execute(insert_query, (
date, process, equipment, title,
phenomenon, cause, action, prevention, int(severity),
embedding
))
conn.commit()
return f"✅ 登録完了: 「{title}」をナレッジベースに保存しました。"
except Exception as e:
return f"### ⚠️ 登録エラー\n詳細: `{repr(e)}`"
finally:
if conn: conn.close()
# --- 検索関数(前回までの機能) ---
def search_troubles(query):
if not query.strip():
return "検索ワードを入力してください。"
conn = None
try:
# 1. 質問文をベクトル化
res = co.embed(
texts=[query],
model='embed-multilingual-v3.0',
input_type='search_query'
)
query_embedding = res.embeddings[0]
# 2. DB接続
conn = psycopg2.connect(**DB_CONFIG, client_encoding='utf8')
cur = conn.cursor(cursor_factory=RealDictCursor)
# Citationのために全カラムを取得するように変更
cur.execute("""
SELECT
id, occurrence_date, process_name, equipment_name, title,
phenomenon, cause, action, prevention, severity,
1 - (embedding <=> %s::vector) AS similarity
FROM factory_troubles
ORDER BY similarity DESC
LIMIT 3
""", (query_embedding,))
results = cur.fetchall()
if not results:
return "該当する事例が見つかりませんでした。"
# 3. 表示用にフォーマット
output = f"## 🔍 類似事例の検索結果(クエリ: {query})\n\n"
for i, r in enumerate(results):
# メインの回答部分
output += f"### {i+1}. {r['title']} (類似度: {r['similarity']:.3f})\n"
output += f"**✅ 推奨される処置:**\n{r['action']}\n\n"
output += f"**⚠️ 今後の防止策:**\n{r['prevention']}\n\n"
# --- Citation (出典詳細情報) ---
output += f"""
<details>
<summary><b>📄 この事例の出典詳細を表示 (ID: {r['id']})</b></summary>
<div style="background-color: #f9f9f9; padding: 15px; border-radius: 8px; border: 1px solid #ddd; color: #333; margin-top: 10px;">
<p><b>📅 発生日:</b> {r['occurrence_date']} | <b>🏢 工程:</b> {r['process_name']} | <b>⚙️ 設備:</b> {r['equipment_name']}</p>
<p><b>🚨 重要度:</b> {r['severity']} / 5</p>
<hr style="border: 0.5px solid #ccc;">
<p><b>【元の現象】</b><br>{r['phenomenon']}</p>
<p><b>【推定原因】</b><br>{r['cause']}</p>
</div>
</details>
\n"""
output += "\n---\n\n"
return output
except Exception as e:
return f"### ⚠️ 検索エラー\n詳細: `{repr(e)}`"
finally:
if conn: conn.close()
# --- Gradio UI 構成 ---
with gr.Blocks(title="工場トラブル・ナレッジ・プラットフォーム", css=".gradio-container {background-color: #f0f2f5}") as demo:
gr.Markdown("# 🛠 工場トラブル・ナレッジ・プラットフォーム")
with gr.Tab("事例を検索する"):
with gr.Column():
search_input = gr.Textbox(label="状況を入力して過去の知見を検索", placeholder="例: モーターの異音...")
search_btn = gr.Button("検索実行", variant="primary")
search_output = gr.Markdown()
search_btn.click(fn=search_troubles, inputs=search_input, outputs=search_output)
with gr.Tab("新規事例を登録する"):
gr.Markdown("### 📝 新しいトラブル報告の入力")
with gr.Row():
date_input = gr.Textbox(label="発生日", value=datetime.now().strftime('%Y-%m-%d'))
process_input = gr.Dropdown(label="工程名", choices=["露光", "エッチング", "成膜", "プレス", "溶接", "切削", "充填", "包装", "組立", "エッチング", "成膜", "調合", "イオン注入", "洗浄", "CMP", "熱処理", "酸洗浄", "スパッター", "封止", "殺菌", "包装", "調合", "搬送", "テスト", "共通"])
severity_input = gr.Slider(label="重要度 (1-5)", minimum=1, maximum=5, step=1, value=3)
equip_input = gr.Textbox(label="設備名")
title_input = gr.Textbox(label="トラブル件名 (Title)")
phenom_input = gr.TextArea(label="現象 (Phenomenon)")
cause_input = gr.TextArea(label="原因 (Cause)")
action_input = gr.TextArea(label="処置 (Action)")
prevent_input = gr.TextArea(label="防止策 (Prevention)")
reg_btn = gr.Button("🚀 データベースに登録", variant="primary")
reg_output = gr.Markdown()
reg_btn.click(
fn=register_trouble,
inputs=[date_input, process_input, equip_input, title_input, phenom_input, cause_input, action_input, prevent_input, severity_input],
outputs=reg_output,
show_progress="full"
)
if __name__ == "__main__":
demo.launch() |