import { useState } from "react"; export default function FiveWhyAnalyzer() { const [finding, setFinding] = useState(""); const [jobContent, setJobContent] = useState(""); const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const [translating, setTranslating] = useState(false); const [error, setError] = useState(""); const [outputLanguage, setOutputLanguage] = useState("zh-TW"); const [currentLanguage, setCurrentLanguage] = useState("zh-TW"); const [showGuide, setShowGuide] = useState(false); const languages = [ { code: "zh-TW", name: "繁體中文", flag: "🇹🇼" }, { code: "zh-CN", name: "简体中文", flag: "🇨🇳" }, { code: "en", name: "English", flag: "🇺🇸" }, { code: "ja", name: "日本語", flag: "🇯🇵" }, { code: "ko", name: "한국어", flag: "🇰🇷" }, { code: "vi", name: "Tiếng Việt", flag: "🇻🇳" }, { code: "th", name: "ภาษาไทย", flag: "🇹🇭" }, ]; const guidelines = [ { title: "精準定義問題", subtitle: "描述現象,而非結論", icon: "🎯", color: "bg-rose-50 border-rose-200", content: "起點若是錯誤,後續分析皆是枉然。必須客觀描述「發生了什麼事」,包含人、事、時、地、物(5W1H)。", example: { bad: "機器壞了", good: "A 機台在下午 2 點運轉時,主軸過熱導致停機" } }, { title: "聚焦流程與系統", subtitle: "而非責備個人", icon: "⚙️", color: "bg-amber-50 border-amber-200", content: "若分析導向「某人不小心」或「某人忘記了」,這不是根本原因。人本來就會犯錯,應追問:「為什麼系統允許這個疏失發生?」", principle: "解決問題的機制,而非責備犯錯的人" }, { title: "基於事實與現場", subtitle: "拒絕猜測", icon: "🔍", color: "bg-emerald-50 border-emerald-200", content: "每一個「為什麼」的回答都必須是經過查證的事實,不能是「我覺得應該是...」或「可能是...」。", principle: "三現主義:現場、現物、現實" }, { title: "邏輯雙向檢核", subtitle: "因果關係必須嚴謹", icon: "🔄", color: "bg-blue-50 border-blue-200", content: "順向:若原因 X 發生,是否必然導致結果 Y?逆向:若消除原因 X,結果 Y 是否就不會發生?", principle: "若無法雙向通過,代表邏輯有斷層" }, { title: "止於可執行對策", subtitle: "永久性對策,非暫時性", icon: "✅", color: "bg-violet-50 border-violet-200", content: "當追問到可以透過具體行動來根除的層次時,就是停止追問的時刻。對策必須是「永久性」的,而非「重新訓練、加強宣導」等暫時性措施。", principle: "目的是解決問題,不是寫報告" } ]; const getLanguageName = (code) => { const lang = languages.find((l) => l.code === code); return lang ? lang.name : code; }; const analyzeWith5Why = async () => { if (!finding.trim() || !jobContent.trim()) { setError("請填寫所有欄位"); return; } setLoading(true); setError(""); setResults([]); const langName = getLanguageName(outputLanguage); const prompt = `你是一位專精於「5 Why 根因分析法」的資深顧問。請嚴格遵循以下五大執行要項進行分析: ## 五大執行要項 ### 1. 精準定義問題(描述現象,而非結論) - 第一步必須客觀描述「發生了什麼事」,而非直接跳入「我認為是甚麼問題」 - 具體化:包含人、事、時、地、物(5W1H) ### 2. 聚焦於「流程」與「系統」,而非「人」 - 若答案是「人為疏失」,請繼續追問:「為什麼系統允許這個疏失發生?」 - 原則:解決問題的機制,而非責備犯錯的人 ### 3. 基於「事實」與「現場」,拒絕「猜測」 - 每一個「為什麼」的回答,都必須是可查證的事實 - 若無法確認,應標註需要驗證的假設 ### 4. 邏輯的「雙向檢核」 - 順向檢查:若原因 X 發生,是否必然導致結果 Y? - 逆向檢查:若消除了原因 X,結果 Y 是否就不會發生? ### 5. 止於「可執行的對策」 - 根本原因必須能對應到一個「永久性對策」(不再發生) - 不僅是「暫時性對策」(如:重新訓練、加強宣導) --- ## 待分析內容 **Finding(發現的問題/現象):** ${finding} **工作內容背景:** ${jobContent} --- ## 輸出要求 請提供 **三個不同角度** 的 5 Why 分析,每個分析從不同的切入點出發(例如:流程面、系統面、管理面、設備面、環境面等)。 注意: - 5 Why 的目的不是「湊滿五個問題」,而是穿透表面症狀直達根本原因 - 若在第 3 或第 4 個 Why 就已找到真正的根本原因,可以停止(設為 null) - 每個 Why 必須標註是「已驗證事實」還是「待驗證假設」 - 最終對策必須是「永久性對策」 ⚠️ 重要:請使用 **${langName}** 語言回覆所有內容。 請用以下 JSON 格式回覆(不要加任何 markdown 標記): { "problemRestatement": "根據 5W1H 重新描述的問題定義", "analyses": [ { "perspective": "分析角度(如:流程面)", "perspectiveIcon": "適合的 emoji", "whys": [ { "level": 1, "question": "為什麼...?", "answer": "因為...", "isVerified": true, "verificationNote": "已確認/需驗證:說明" } ], "rootCause": "根本原因(系統/流程層面)", "logicCheck": { "forward": "順向檢核:如果[原因]發生,則[結果]必然發生", "backward": "逆向檢核:如果消除[原因],則[結果]不會發生", "isValid": true }, "countermeasure": { "permanent": "永久性對策(系統性解決方案)", "actionItems": ["具體行動項目1", "具體行動項目2"], "avoidList": ["避免的暫時性做法(如:加強宣導)"] } } ] }`; try { const response = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 6000, messages: [{ role: "user", content: prompt }], }), }); const data = await response.json(); const text = data.content .map((item) => (item.type === "text" ? item.text : "")) .join(""); const clean = text.replace(/```json|```/g, "").trim(); const parsed = JSON.parse(clean); setResults(parsed); setCurrentLanguage(outputLanguage); } catch (err) { setError("分析失敗,請稍後再試:" + err.message); } finally { setLoading(false); } }; const translateResults = async (targetLang) => { if (!results.analyses || targetLang === currentLanguage) return; setTranslating(true); setError(""); const langName = getLanguageName(targetLang); const prompt = `請將以下 5 Why 分析結果翻譯成 **${langName}**。 原始內容: ${JSON.stringify(results, null, 2)} 請保持完全相同的 JSON 結構,只翻譯文字內容。 請用以下 JSON 格式回覆(不要加任何 markdown 標記): { "problemRestatement": "...", "analyses": [...] }`; try { const response = await fetch("https://api.anthropic.com/v1/messages", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: "claude-sonnet-4-20250514", max_tokens: 6000, messages: [{ role: "user", content: prompt }], }), }); const data = await response.json(); const text = data.content .map((item) => (item.type === "text" ? item.text : "")) .join(""); const clean = text.replace(/```json|```/g, "").trim(); const parsed = JSON.parse(clean); setResults(parsed); setCurrentLanguage(targetLang); } catch (err) { setError("翻譯失敗:" + err.message); } finally { setTranslating(false); } }; const cardColors = [ { header: "bg-blue-500", headerText: "text-white", border: "border-blue-200" }, { header: "bg-violet-500", headerText: "text-white", border: "border-violet-200" }, { header: "bg-teal-500", headerText: "text-white", border: "border-teal-200" }, ]; return (
{/* Header */}

🔍 5 Why 根因分析器

穿透問題表面,直達根本原因,產出永久性對策

{/* Guidelines Toggle */}
{showGuide && (
{guidelines.map((guide, idx) => (
{guide.icon}

{guide.title}

{guide.subtitle}

{guide.content}

{guide.example && (
❌ {guide.example.bad}
⭕ {guide.example.good}
)} {guide.principle && (
💡 {guide.principle}
)}
))}
)}
{/* Input Section */}

請具體描述現象(5W1H):何人、何事、何時、何地、如何發生