kofdai commited on
Commit
5746029
·
verified ·
1 Parent(s): 7cd89b8

Upload reasoning_chain_extractor.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. 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
+ # 関連概念: ['心電図']