Wen1201/BayesianPyMc1
0
1import google.generativeai as genai2import json3import re4import graphviz5import io6from PIL import Image7 8class BayesianLLMAssistant:9 """10 貝氏階層模型 LLM 問答助手(支援動態 DAG 生成)11 協助用戶理解貝氏分析結果,並可根據描述生成客製化 DAG 圖12 """13 14 def __init__(self, api_key, session_id, api_provider="Google Gemini"):15 """16 初始化 LLM 助手17 18 Args:19 api_key: API key (Gemini 或 Claude)20 session_id: 唯一的 session 識別碼21 api_provider: API 提供商 ("Google Gemini" 或 "Anthropic Claude")22 """23 self.api_provider = api_provider24 self.session_id = session_id25 self.conversation_history = []26 27 if api_provider == "Google Gemini":28 import google.generativeai as genai29 genai.configure(api_key=api_key)30 self.model = genai.GenerativeModel('gemini-2.0-flash-exp')31 self.client = None32 else: # Anthropic Claude33 import anthropic34 self.client = anthropic.Anthropic(api_key=api_key)35 self.model_name = "claude-sonnet-4-5-20250929"36 self.model = None37 38 39 # 系統提示詞(加入 DAG 生成能力)40 # 完整修改後的 system_prompt41 # 替換 bayesian_llm_assistant.py 第 40-181 行42 43 self.system_prompt = """You are an expert Bayesian statistician specializing in hierarchical models and meta-analysis, particularly in the context of Pokémon battle statistics.44 45**IMPORTANT - Language Instruction:**46- Always respond in the SAME language as the user's question47- If user asks in Traditional Chinese (繁體中文), respond in Traditional Chinese48- If user asks in English, respond in English49- Maintain language consistency throughout the conversation50 51你是一位精通貝氏階層模型和統合分析的統計專家,特別專注於寶可夢對戰統計分析。52 53Your role is to help users understand Bayesian hierarchical model results analyzing 54win rate comparisons between Fire-type and Water-type Pokémon across different matchup pairs.55你的角色是幫助使用者理解貝氏階層模型分析結果,56了解火系與水系寶可夢在不同配對組合下的勝率比較。57 58**NEW CAPABILITY: DAG Diagram Generation | 新能力:DAG 圖生成**59When users ask you to draw, create, or visualize a DAG (Directed Acyclic Graph) or model structure, you can generate Graphviz DOT code.60當用戶要求你繪製、創建或視覺化 DAG(有向無環圖)或模型結構時,你可以生成 Graphviz DOT 代碼。61 62**How to generate DAG code:**631. Detect requests like: "draw a DAG", "show me the model structure", "visualize the relationships", "畫一個 DAG 圖", "顯示模型結構"642. Generate Graphviz DOT code wrapped in special tags:65 ```graphviz66 digraph G {67 // Your DOT code here68 }69 ```703. The system will automatically render it as an image71 72**IMPORTANT - Font and Label Instructions for DAG:**73- NEVER use Chinese characters in node labels74- Use ONLY English labels, or use English + romanized Chinese75- DO NOT set fontname in the graph76- Example of good labels: "d (overall effect)" or "delta[i] (pair-specific)"77- Example of bad labels: "整體效應" or any Chinese text78 79**重要 - DAG 圖的字型和標籤指示:**80- 絕對不要在節點標籤中使用中文字81- 只使用英文標籤,或使用「英文 + 拼音」82- 不要設定 fontname83- 好的標籤範例:"d (overall effect)" 或 "delta[i] (pair-specific)"84- 不好的標籤範例:"整體效應" 或任何中文85 86**Example DAG code for Bayesian hierarchical model:**87```graphviz88digraph BayesianModel {89 rankdir=TB;90 node [shape=ellipse, style=filled, fillcolor=lightblue];91 92 // Priors93 d [label="d\n(Fire vs Water overall)", fillcolor=lightyellow];94 tau [label="tau\n(precision)", fillcolor=lightyellow];95 sigma [label="sigma = 1/√tau", shape=diamond, fillcolor=lightgray];96 97 // Hierarchy98 d -> delta [label="mean"];99 tau -> delta [label="precision"];100 sigma -> delta [style=dashed];101 102 delta [label="delta[i]\n(pair-specific)", fillcolor=lightgreen];103 mu [label="mu[i]\n(baseline)", fillcolor=lightyellow];104 105 // Likelihood106 delta -> pt [label="effect"];107 mu -> pc;108 mu -> pt;109 110 pc [label="pc[i]\n(Water win rate)", shape=diamond, fillcolor=lightgray];111 pt [label="pt[i]\n(Fire win rate)", shape=diamond, fillcolor=lightgray];112 113 pc -> rc_obs [label="probability"];114 pt -> rt_obs [label="probability"];115 116 rc_obs [label="rc_obs[i]\n(Water wins)", shape=box, fillcolor=lightcoral];117 rt_obs [label="rt_obs[i]\n(Fire wins)", shape=box, fillcolor=lightcoral];118}119```120 121You should:1221. Explain Bayesian concepts in simple, accessible terms1232. Interpret posterior distributions, HDI (Highest Density Interval), and credible intervals1243. Explain hierarchical structure and why it's useful1254. Help users understand heterogeneity (sigma) between different matchup pairs1265. Discuss the practical significance of Fire vs Water type advantages1276. Provide insights about which matchup pairs favor Fire-types the most1287. Suggest team building strategies based on the statistical findings1298. Clarify differences between Bayesian and frequentist approaches1309. Explain MCMC diagnostics (R-hat, ESS) when relevant13110. **Generate custom DAG diagrams based on user descriptions**132 133你應該:1341. 用簡單易懂的方式解釋貝氏概念1352. 詮釋後驗分佈、HDI(最高密度區間)和可信區間1363. 解釋階層結構及其優勢1374. 幫助使用者理解不同配對間的異質性(sigma)1385. 討論火系與水系屬性優劣勢的實際意義1396. 提供哪些配對組合中火系最具優勢的見解1407. 根據統計發現提出組隊策略建議1418. 說明貝氏方法與頻率論方法的差異1429. 適時解釋 MCMC 診斷指標(R-hat、ESS)14310. **根據用戶描述生成客製化 DAG 圖**144 145Key concepts to explain when relevant:146- **Bayesian Hierarchical Model**: Borrows strength across matchup pairs, shrinkage effect147- **Prior & Posterior**: How data updates beliefs148- **HDI (Highest Density Interval)**: 95% most credible values149- **d (overall effect)**: Average log odds ratio of Fire vs Water across all pairs150- **sigma (between-pair variation)**: How much different matchup pairs vary in Fire advantage151- **delta (pair-specific effects)**: Each matchup pair's individual Fire advantage/disadvantage152- **Odds Ratio**: exp(d) - how much more likely Fire-types are to win compared to Water-types153- **MCMC**: Markov Chain Monte Carlo sampling method154- **Convergence**: R-hat < 1.1, good ESS (effective sample size)155- **DAG (Directed Acyclic Graph)**: Visual representation of model structure156 157重要概念解釋(當相關時):158- **貝氏階層模型**:跨配對借用資訊,收縮效應159- **先驗與後驗**:資料如何更新信念160- **HDI(最高密度區間)**:95% 最可信的數值範圍161- **d(整體效應)**:火系相對於水系的平均對數勝算比(跨所有配對)162- **sigma(配對間變異)**:不同配對組合的火系優勢差異程度163- **delta(配對特定效應)**:每組配對的個別火系優勢/劣勢164- **勝算比**:exp(d) - 火系相對於水系獲勝的可能性倍數165- **MCMC**:馬可夫鏈蒙地卡羅抽樣方法166- **收斂性**:R-hat < 1.1,良好的 ESS(有效樣本數)167- **DAG(有向無環圖)**:模型結構的視覺化表示168 169When discussing Pokémon type matchups:170- Connect statistical findings to type advantage mechanics (Water typically beats Fire in core games)171- Explain why Fire vs Water matchups show certain patterns172- Discuss individual matchup variations and their causes (e.g., specific Pokémon abilities, stats)173- Identify which Fire/Water Pokémon pairs show unusual results (Fire winning despite type disadvantage)174- Consider team building and type coverage implications175 176討論寶可夢屬性對抗時:177- 將統計發現連結到屬性相剋機制(水系通常剋火系)178- 解釋火系對水系的對戰模式為何呈現特定趨勢179- 討論個別配對的變異及其可能原因(例如特殊能力、數值差異)180- 識別哪些火/水系配對顯示異常結果(火系儘管屬性不利仍獲勝)181- 考慮組隊和屬性覆蓋的影響182 183Always be clear, educational, and engaging. Use examples when helpful.184Format responses with proper markdown for better readability.185 186請務必清晰、具教育性、引人入勝。適時使用範例說明。使用適當的 Markdown 格式以提升可讀性。"""187 188 def get_response(self, user_message, analysis_results=None):189 """190 獲取 AI 回應(支援 DAG 生成)191 192 Args:193 user_message: 用戶訊息194 analysis_results: 分析結果字典(可選)195 196 Returns:197 tuple: (回應文字, DAG 圖片或 None)198 """199 # 準備上下文資訊200 context = ""201 if analysis_results:202 context = self._prepare_context(analysis_results)203 204 # 添加用戶訊息到歷史205 self.conversation_history.append({206 "role": "user",207 "content": user_message208 })209 210 try:211 # 構建完整的提示詞212 full_prompt = self.system_prompt213 214 if context:215 full_prompt += f"\n\n## Current Analysis Context:\n{context}"216 217 # 構建對話歷史文字218 conversation_text = "\n\n## Conversation History:\n"219 for msg in self.conversation_history[:-1]:220 role = "User" if msg["role"] == "user" else "Assistant"221 conversation_text += f"\n{role}: {msg['content']}\n"222 223 # 組合最終提示詞224 final_prompt = full_prompt + conversation_text + f"\nUser: {user_message}\n\nAssistant:"225 226 227 # 調用對應的 API228 if self.api_provider == "Google Gemini":229 response = self.model.generate_content(230 final_prompt,231 generation_config=genai.types.GenerationConfig(232 temperature=0.7,233 max_output_tokens=4000,234 )235 )236 assistant_message = response.text237 238 else: # Anthropic Claude239 response = self.client.messages.create(240 model=self.model_name,241 max_tokens=4000,242 temperature=0.7,243 system=self.system_prompt,244 messages=[245 {"role": "user", "content": final_prompt}246 ]247 )248 assistant_message = response.content[0].text 249 250 # 檢查是否包含 Graphviz 代碼251 dag_image = self._extract_and_render_dag(assistant_message)252 253 # 添加助手回應到歷史254 self.conversation_history.append({255 "role": "assistant",256 "content": assistant_message257 })258 259 return assistant_message, dag_image260 261 except Exception as e:262 error_msg = f"❌ Error: {str(e)}\n\nPlease check your API key and try again."263 return error_msg, None264 265 266 267 def _extract_and_render_dag(self, text):268 """269 從文字中提取 Graphviz 代碼並渲染成圖片270 271 Args:272 text: 包含可能的 Graphviz 代碼的文字273 274 Returns:275 PIL Image 或 None276 """277 # 方法 1: 嘗試提取 ```graphviz ... ``` 格式278 pattern1 = r'```graphviz\s*\n(.*?)\n```'279 matches = re.findall(pattern1, text, re.DOTALL)280 281 if matches:282 dot_code = matches[0]283 else:284 # 方法 2: 嘗試提取 digraph ... } 格式(沒有 markdown 包裹)285 #pattern2 = r'(digraph\s+\w+\s*\{.*?\n\})'286 pattern2 = r'(digraph\s+\w+\s*\{.*\})'287 matches = re.findall(pattern2, text, re.DOTALL)288 289 if not matches:290 return None291 292 dot_code = matches[0]293 294 try:295 # 使用 Graphviz 渲染296 graph = graphviz.Source(dot_code)297 png_bytes = graph.pipe(format='png')298 299 # 轉換為 PIL Image300 img = Image.open(io.BytesIO(png_bytes))301 302 return img303 304 except Exception as e:305 print(f"Failed to render DAG: {e}")306 return None 307 308 309 def _prepare_context(self, results):310 """準備分析結果的上下文資訊"""311 312 if not results:313 return "目前尚無分析結果。No analysis results available yet."314 315 overall = results['overall']316 interp = results['interpretation']317 diag = results['diagnostics']318 319 # 找出顯著的配對320 sig_types = [321 results['trial_labels'][i] 322 for i, sig in enumerate(results['by_trial']['delta_significant']) 323 if sig324 ]325 326 context = f"""327## Current Bayesian Hierarchical Model Analysis | 目前的貝氏階層模型分析328 329### Overall Effect | 整體效應330- **d (Log Odds Ratio) | d(對數勝算比)**: 331 - Mean | 平均: {overall['d_mean']:.4f}332 - SD | 標準差: {overall['d_sd']:.4f}333 - 95% HDI: [{overall['d_hdi_low']:.4f}, {overall['d_hdi_high']:.4f}]334 335- **sigma (Between-pair Variation) | sigma(配對間變異)**: 336 - Mean | 平均: {overall['sigma_mean']:.4f}337 - SD | 標準差: {overall['sigma_sd']:.4f}338 - 95% HDI: [{overall['sigma_hdi_low']:.4f}, {overall['sigma_hdi_high']:.4f}]339 340- **Odds Ratio | 勝算比**: 341 - Mean | 平均: {overall['or_mean']:.4f}342 - SD | 標準差: {overall['or_sd']:.4f}343 - 95% HDI: [{overall['or_hdi_low']:.4f}, {overall['or_hdi_high']:.4f}]344 345### Model Diagnostics | 模型診斷346- **R-hat (d)**: {f"{diag['rhat_d']:.4f}" if diag['rhat_d'] is not None else 'N/A'} {'✓' if diag['rhat_d'] and diag['rhat_d'] < 1.1 else '✗'}347- **R-hat (sigma)**: {f"{diag['rhat_sigma']:.4f}" if diag['rhat_sigma'] is not None else 'N/A'} {'✓' if diag['rhat_sigma'] and diag['rhat_sigma'] < 1.1 else '✗'}348- **ESS (d)**: {int(diag['ess_d']) if diag['ess_d'] is not None else 'N/A'}349- **ESS (sigma)**: {int(diag['ess_sigma']) if diag['ess_sigma'] is not None else 'N/A'}350- **Convergence | 收斂狀態**: {'✓ Converged 已收斂' if diag['converged'] else '✗ Not Converged 未收斂'}351 352### Interpretation | 結果解釋353- **Overall Effect | 整體效應**: {interp['overall_effect']}354- **Significance | 顯著性**: {interp['overall_significance']}355- **Effect Size | 效果大小**: {interp['effect_size']}356- **Heterogeneity | 異質性**: {interp['heterogeneity']}357 358### Significant Pairs | 顯著的配對359{len(sig_types)} out of {results['n_trials']} pairs show significant Fire advantage:360{len(sig_types)} 組配對(共 {results['n_trials']} 組)顯示顯著的火系優勢:361{', '.join(sig_types) if sig_types else 'None 無'}362 363### Number of Pairs Analyzed | 分析的配對數量364{results['n_trials']} pairs in total 共 {results['n_trials']} 組配對365 366### Key Finding | 關鍵發現367{368 f"On average, Fire-type Pokémon are {overall['or_mean']:.2f} times more likely to win compared to Water-type (95% HDI: [{overall['or_hdi_low']:.2f}, {overall['or_hdi_high']:.2f}]). 平均而言,火系寶可夢獲勝的可能性是水系的 {overall['or_mean']:.2f} 倍 (95% HDI: [{overall['or_hdi_low']:.2f}, {overall['or_hdi_high']:.2f}])。"369 370 if overall['or_mean'] > 1371 else f"Interestingly, Water-type Pokémon show advantage over Fire-type despite type matchup, with OR = {overall['or_mean']:.2f}. 有趣的是,儘管屬性相剋,水系寶可夢相對火系仍顯示優勢,OR = {overall['or_mean']:.2f}。"372}373 374The variation between matchup pairs (sigma = {overall['sigma_mean']:.3f}) indicates {interp['heterogeneity'].lower()}.375配對間的變異(sigma = {overall['sigma_mean']:.3f})表示{interp['heterogeneity'].lower()}。376"""377 return context378 379 def draw_custom_dag(self, description):380 """381 根據用戶描述生成客製化 DAG 圖382 383 Args:384 description: 用戶對 DAG 的描述385 386 Returns:387 tuple: (解釋文字, DAG 圖片或 None)388 """389 prompt = f"""Based on the following description, generate a Graphviz DOT code for a DAG diagram:390 391User description: {description}392 393Please:3941. Create a clear and informative DAG3952. Use appropriate node shapes (ellipse for random variables, box for observed data, diamond for deterministic nodes)3963. Use different colors to distinguish node types3974. **CRITICAL: Use ONLY English labels - NO Chinese characters in node labels**3985. Add labels to explain what each node represents (in English)3996. Wrap your DOT code in ```graphviz ``` tags4007. Provide a brief explanation in Traditional Chinese about what the diagram shows401 402根據以下描述,生成 Graphviz DOT 代碼的 DAG 圖:403 404用戶描述:{description}405 406請:4071. 創建清晰且有資訊性的 DAG4082. 使用適當的節點形狀(橢圓代表隨機變數,矩形代表觀測資料,菱形代表確定性節點)4093. 使用不同顏色區分節點類型4104. **重要:節點標籤必須使用英文,不能使用中文**4115. 添加標籤說明每個節點代表什麼(用英文)4126. 將 DOT 代碼包在 ```graphviz ``` 標籤中4137. 用繁體中文簡要說明圖表顯示什麼"""414 415 return self.get_response(prompt, None)416 417 # 保留原有的所有方法...418 def generate_summary(self, analysis_results):419 """自動生成分析結果總結"""420 421 summary_prompt = """請根據提供的貝氏階層模型分析結果生成一份完整的總結報告,包含:422 4231. **模型目的**:簡述這個階層模型在分析什麼(火系 vs 水系配對比較)4242. **整體發現**:425 - 火系相對於水系的整體勝率優勢如何?426 - d 和勝算比告訴我們什麼?427 - HDI 的意義是什麼?4283. **配對間差異**:429 - sigma 告訴我們什麼?430 - 哪些配對組合中火系特別強勢?哪些則較弱?4314. **模型品質**:432 - 模型收斂得好嗎?(R-hat、ESS)433 - 結果可信嗎?4345. **實戰啟示**:435 - 訓練師如何運用這些資訊?436 - 在火水對抗中,應該選擇哪些特定的寶可夢?437 438請用清楚的繁體中文 Markdown 格式撰寫,包含適當的章節標題。"""439 440 text, _ = self.get_response(summary_prompt, analysis_results)441 return text442 443 def explain_metric(self, metric_name, analysis_results):444 """解釋特定指標"""445 446 metric_explanations = {447 'd': 'd (火系 vs 水系整體對數勝算比)',448 'sigma': 'sigma (配對間變異)',449 'or_speed': 'Odds Ratio (火系對水系勝算比)',450 'hdi': '95% HDI (最高密度區間)',451 'delta': 'delta (配對特定效應)',452 'rhat': 'R-hat (收斂診斷)',453 'ess': 'ESS (有效樣本數)'454 }455 456 metric_display = metric_explanations.get(metric_name, metric_name)457 458 explain_prompt = f"""請在這次貝氏階層模型分析的脈絡下,解釋以下指標:459 460指標:{metric_display}461 462請包含:4631. 這個指標在貝氏統計中測量什麼?4642. 在本次分析中得到的數值是多少?4653. 如何從寶可夢對戰的角度詮釋這個數值?4664. 與頻率論統計的對應指標有何不同?4675. 有什麼需要注意的限制或注意事項?468 469請用繁體中文回答。"""470 471 text, _ = self.get_response(explain_prompt, analysis_results)472 return text473 474 def explain_bayesian_vs_frequentist(self):475 """解釋貝氏與頻率論的差異"""476 477 explain_prompt = """請用簡單的方式解釋貝氏統計和頻率論統計的差異,特別是在寶可夢對戰分析的情境下。478 479請涵蓋:4801. 兩者的根本哲學差異是什麼?4812. p 值 vs HDI(可信區間)有什麼不同?4823. 為什麼我們用階層模型來分析多組配對?4834. 貝氏方法的優勢和限制是什麼?4845. 什麼時候該用貝氏、什麼時候該用頻率論?485 486請用寶可夢的實際例子讓說明更具體易懂,全程使用繁體中文。"""487 488 text, _ = self.get_response(explain_prompt, None)489 return text490 491 def explain_hierarchical_model(self):492 """解釋階層模型的概念"""493 494 explain_prompt = """請用簡單的方式解釋貝氏階層模型,特別是在火系對水系配對分析的情境下。495 496請涵蓋:4971. 什麼是階層模型?為什麼要用階層結構?4982. 「借用資訊」(borrowing strength) 是什麼意思?499 - 在本分析中,如何跨 46 組配對借用資訊?5003. 收縮效應 (shrinkage) 如何運作?501 - 為什麼某些極端的配對結果會被「拉回」?5024. 為什麼階層模型適合分析多組配對?5035. d(整體火系優勢)、sigma(配對間變異)、delta(各配對特定效應)之間的關係是什麼?504 505請用火系對水系的實際配對例子讓說明更具體易懂,全程使用繁體中文。"""506 507 text, _ = self.get_response(explain_prompt, None)508 return text509 510 def battle_strategy_advice(self, analysis_results):511 """提供對戰策略建議"""512 513 strategy_prompt = """根據貝氏階層模型的分析結果,請為寶可夢訓練師提供實際的組隊策略建議。514 515請考慮:5161. 整體而言,火系對水系的勝率如何?5172. 哪些火系寶可夢在對抗水系時特別強?(對應 delta 顯著為正的配對)5183. 是否有火系寶可夢即使對抗水系仍表現不佳?(delta 顯著為負)5194. 訓練師在選擇火系對抗水系時應該注意什麼?5205. 對競技對戰的組隊和屬性覆蓋有什麼啟示?5216. 有沒有出乎意料的發現?(例如某些火系特別強/弱)522 523請具體且可操作,使用繁體中文回答。"""524 525 text, _ = self.get_response(strategy_prompt, analysis_results)526 return text527 528 def compare_types(self, analysis_results):529 """比較不同配對"""530 531 compare_prompt = """請比較分析結果中不同配對組合的火系優勢差異。532 533請說明:5341. 哪些配對中火系特別強勢?可能的原因是什麼?535 - 考慮:特殊能力、數值優勢、招式組合5362. 哪些配對中火系反而處於劣勢?為什麼?5373. 配對間的異質性(sigma)告訴我們什麼?538 - 是否某些火/水系寶可夢特別能打破屬性相剋?5394. 有沒有令人意外的發現?540 - 例如:某個火系儘管屬性不利仍大幅獲勝541 - 或某個火系表現比預期差很多5425. 這些差異對組隊策略有什麼啟示?543 - 如何針對性地選擇火系來對抗水系?544 545請用繁體中文回答。"""546 547 text, _ = self.get_response(compare_prompt, analysis_results)548 return text549 550 def reset_conversation(self):551 """重置對話歷史"""552 self.conversation_history = []