Upload reasoning_chain_extractor.py with huggingface_hub
Browse files- reasoning_chain_extractor.py +160 -0
reasoning_chain_extractor.py
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
def extract_concepts(text: str) -> list:
|
| 2 |
+
"""
|
| 3 |
+
文章から医学的概念を抽出します。
|
| 4 |
+
この関数はダミー実装であり、実際のプロジェクトでは
|
| 5 |
+
MeSHやUMLSなどの医学オントロジー、あるいはより高度なNERモデルを
|
| 6 |
+
使用して実装する必要があります。
|
| 7 |
+
|
| 8 |
+
Args:
|
| 9 |
+
text (str): 分析対象のテキスト。
|
| 10 |
+
|
| 11 |
+
Returns:
|
| 12 |
+
list: 抽出された概念のリスト。
|
| 13 |
+
"""
|
| 14 |
+
# プレースホルダー実装
|
| 15 |
+
concepts = []
|
| 16 |
+
if "心筋梗塞" in text:
|
| 17 |
+
concepts.append("心筋梗塞")
|
| 18 |
+
if "心電図" in text:
|
| 19 |
+
concepts.append("心電図")
|
| 20 |
+
if "トロポニン" in text:
|
| 21 |
+
concepts.append("トロポニン")
|
| 22 |
+
return concepts
|
| 23 |
+
|
| 24 |
+
def estimate_confidence(sentence: str) -> float:
|
| 25 |
+
"""
|
| 26 |
+
文中の表現から確実性を推定します。
|
| 27 |
+
(0.0 - 1.0の範囲のスコアを返す)
|
| 28 |
+
"""
|
| 29 |
+
high_confidence_phrases = [
|
| 30 |
+
"必ず", "常に", "確実に", "証明されている", "である"
|
| 31 |
+
]
|
| 32 |
+
medium_confidence_phrases = [
|
| 33 |
+
"通常は", "多くの場合", "一般的に", "考えられている"
|
| 34 |
+
]
|
| 35 |
+
low_confidence_phrases = [
|
| 36 |
+
"かもしれない", "可能性がある", "推測される", "示唆される", "仮説として"
|
| 37 |
+
]
|
| 38 |
+
|
| 39 |
+
# 完全な一致ではなく、部分的な一致を許容するため 'in' を使用
|
| 40 |
+
if any(phrase in sentence for phrase in high_confidence_phrases):
|
| 41 |
+
return 0.85
|
| 42 |
+
elif any(phrase in sentence for phrase in medium_confidence_phrases):
|
| 43 |
+
return 0.60
|
| 44 |
+
elif any(phrase in sentence for phrase in low_confidence_phrases):
|
| 45 |
+
return 0.35
|
| 46 |
+
else:
|
| 47 |
+
# デフォルトは中間的な信頼度よりやや下
|
| 48 |
+
return 0.50
|
| 49 |
+
|
| 50 |
+
def classify_depth(sentence: str) -> int:
|
| 51 |
+
"""
|
| 52 |
+
文の内容から医学的な深さを5段階で分類します。
|
| 53 |
+
1=症状, 2=診断, 3=機序, 4=分子, 5=複合
|
| 54 |
+
"""
|
| 55 |
+
depth_keywords = {
|
| 56 |
+
1: ["症状", "訴え", "患者が感じる", "胸痛", "息切れ"],
|
| 57 |
+
2: ["検査", "所見", "診断基準", "心電図", "バイオマーカー", "トロポニン"],
|
| 58 |
+
3: ["メカニズム", "機序", "なぜ", "原因", "血流", "虚血"],
|
| 59 |
+
4: ["分子", "遺伝子", "酵素", "受容体", "細胞", "イオン"],
|
| 60 |
+
5: ["複合", "相互作用", "システム", "統合", "複数の因子"]
|
| 61 |
+
}
|
| 62 |
+
|
| 63 |
+
for level, keywords in reversed(list(depth_keywords.items())):
|
| 64 |
+
if any(keyword in sentence for keyword in keywords):
|
| 65 |
+
return level
|
| 66 |
+
|
| 67 |
+
return 2 # デフォルト:診断レベル
|
| 68 |
+
|
| 69 |
+
def extract_reasoning_chain(deepseek_response: dict) -> list:
|
| 70 |
+
"""
|
| 71 |
+
DeepSeek R1の<thinking>セクションから推論ステップを抽出します。
|
| 72 |
+
|
| 73 |
+
Args:
|
| 74 |
+
deepseek_response (dict): 'thinking'キーを含むDeepSeek APIのレスポンス。
|
| 75 |
+
|
| 76 |
+
Returns:
|
| 77 |
+
list: 各ステップが辞書として格納されたリスト。
|
| 78 |
+
"""
|
| 79 |
+
thinking_text = deepseek_response.get("thinking", "")
|
| 80 |
+
if not thinking_text:
|
| 81 |
+
return []
|
| 82 |
+
|
| 83 |
+
# 推論の区切りとなりうるマーカー
|
| 84 |
+
reasoning_markers = [
|
| 85 |
+
"まず", "次に", "その結果", "さらに", "これは~という理由で",
|
| 86 |
+
"~を考えると", "~に基づいて", "したがって", "一方で"
|
| 87 |
+
]
|
| 88 |
+
|
| 89 |
+
# テキストを文(「。」)で分割
|
| 90 |
+
sentences = thinking_text.replace("。。", "。\n").split("\n")
|
| 91 |
+
sentences = [s.strip() for s in sentences if s.strip()]
|
| 92 |
+
|
| 93 |
+
reasoning_steps = []
|
| 94 |
+
current_step_text = ""
|
| 95 |
+
|
| 96 |
+
for i, sentence in enumerate(sentences):
|
| 97 |
+
# マーカーで始まる場合、または前のステップが長すぎる場合に新しいステップを開始
|
| 98 |
+
is_new_step = any(sentence.startswith(marker) for marker in reasoning_markers)
|
| 99 |
+
if is_new_step and current_step_text:
|
| 100 |
+
reasoning_steps.append(current_step_text)
|
| 101 |
+
current_step_text = sentence
|
| 102 |
+
else:
|
| 103 |
+
current_step_text += (" " + sentence) if current_step_text else sentence
|
| 104 |
+
|
| 105 |
+
if current_step_text:
|
| 106 |
+
reasoning_steps.append(current_step_text)
|
| 107 |
+
|
| 108 |
+
# 抽出したステップを構造化データに変換
|
| 109 |
+
structured_steps = []
|
| 110 |
+
for i, step_text in enumerate(reasoning_steps):
|
| 111 |
+
step = {
|
| 112 |
+
"sequence": i,
|
| 113 |
+
"text": step_text,
|
| 114 |
+
"confidence": estimate_confidence(step_text),
|
| 115 |
+
"concepts": extract_concepts(step_text),
|
| 116 |
+
"depth_level": classify_depth(step_text)
|
| 117 |
+
}
|
| 118 |
+
structured_steps.append(step)
|
| 119 |
+
|
| 120 |
+
return structured_steps
|
| 121 |
+
|
| 122 |
+
# --- 使用例 ---
|
| 123 |
+
if __name__ == "__main__":
|
| 124 |
+
# deepseek_prompt_templates.py からのダミーレスポンスを想定
|
| 125 |
+
dummy_response = {
|
| 126 |
+
'thinking': 'まず、心筋梗塞の定義から始めます。これは心筋への血流が途絶えることで心筋が壊死する状態です。次に、診断のゴールド���タンダードであるトロポニン測定について考慮します。これは~という理由で重要です。さらに心電図の変化も重要な所見です。ST上昇が見られる場合、緊急性が高いと判断されます。',
|
| 127 |
+
'response': '...'
|
| 128 |
+
}
|
| 129 |
+
|
| 130 |
+
print("--- 推論チェーンの抽出テスト ---")
|
| 131 |
+
reasoning_chain = extract_reasoning_chain(dummy_response)
|
| 132 |
+
|
| 133 |
+
for step in reasoning_chain:
|
| 134 |
+
print(f"\nステップ {step['sequence']}:")
|
| 135 |
+
print(f" テキスト: {step['text']}")
|
| 136 |
+
print(f" 信頼度: {step['confidence']:.2f}")
|
| 137 |
+
print(f" 深さレベル: {step['depth_level']}")
|
| 138 |
+
print(f" 関連概念: {step['concepts']}")
|
| 139 |
+
|
| 140 |
+
# 出力例:
|
| 141 |
+
#
|
| 142 |
+
# --- 推論チェーンの抽出テスト ---
|
| 143 |
+
#
|
| 144 |
+
# ステップ 0:
|
| 145 |
+
# テキスト: まず、心筋梗塞の定義から始めます。 これは心筋への血流が途絶えることで心筋が壊死する状態です。
|
| 146 |
+
# 信頼度: 0.85
|
| 147 |
+
# 深さレベル: 3
|
| 148 |
+
# 関連概念: ['心筋梗塞']
|
| 149 |
+
#
|
| 150 |
+
# ステップ 1:
|
| 151 |
+
# テキスト: 次に、診断のゴールドスタンダードであるトロポニン測定について考慮します。 これは~という理由で重要です。
|
| 152 |
+
# 信頼度: 0.85
|
| 153 |
+
# 深さレベル: 2
|
| 154 |
+
# 関連概念: ['トロポニン']
|
| 155 |
+
#
|
| 156 |
+
# ステップ 2:
|
| 157 |
+
# テキスト: さらに心電図の変化も重要な所見です。 ST上昇が見られる場合、緊急性が高いと判断されます。
|
| 158 |
+
# 信頼度: 0.85
|
| 159 |
+
# 深さレベル: 2
|
| 160 |
+
# 関連概念: ['心電図']
|