Satoc commited on
Commit
d35c258
·
1 Parent(s): f2a4871

reverse old app

Browse files
OpenAITools/CrinicalTrialTools.py CHANGED
@@ -2,73 +2,35 @@ from langchain_community.agent_toolkits import create_sql_agent
2
  from langchain_openai import ChatOpenAI
3
  from langchain_groq import ChatGroq
4
  from langchain_core.prompts import ChatPromptTemplate
5
- # 修正: pydantic v1の非推奨警告を解決
6
- try:
7
- from pydantic import BaseModel, Field
8
- except ImportError:
9
- from langchain_core.pydantic_v1 import BaseModel, Field
10
-
11
  import pandas as pd
12
- import time
13
- import re
14
- from typing import Optional
15
 
16
  from langchain.text_splitter import RecursiveCharacterTextSplitter
17
  from langchain_community.vectorstores import Chroma
18
- # 修正: HuggingFaceEmbeddingsの非推奨警告を解決
19
- try:
20
- from langchain_community.embeddings import HuggingFaceEmbeddings
21
- except ImportError:
22
- from langchain.embeddings import HuggingFaceEmbeddings
23
-
24
  from langchain_core.runnables import RunnablePassthrough
25
  from langchain_core.output_parsers import StrOutputParser
26
 
27
- # 修正: モジュールレベルでの初期化を削除
28
- # gpt = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
29
 
30
- ## Database関連のインポート
 
 
 
 
31
  from langchain_community.utilities import SQLDatabase
32
  from sqlalchemy import create_engine
 
33
  from langchain.prompts import ChatPromptTemplate
34
  from langchain.schema import SystemMessage
35
  from langchain_core.prompts import MessagesPlaceholder
 
36
 
37
  from OpenAITools.FetchTools import fetch_clinical_trials, fetch_clinical_trials_jp
38
 
39
- # GPT初期化を関数として追加
40
- def get_openai_client():
41
- """OpenAIクライアントを安全に初期化"""
42
- try:
43
- return ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
44
- except Exception as e:
45
- print(f"OpenAI初期化エラー: {e}")
46
- return None
47
-
48
- # エラーハンドリング用のデコレータ
49
- def retry_on_error(max_retries=3, delay=1):
50
- """エラー時のリトライデコレータ"""
51
- def decorator(func):
52
- def wrapper(*args, **kwargs):
53
- for attempt in range(max_retries):
54
- try:
55
- return func(*args, **kwargs)
56
- except Exception as e:
57
- if attempt < max_retries - 1:
58
- print(f"エラーが発生しました (試行 {attempt + 1}/{max_retries}): {e}")
59
- if "no healthy upstream" in str(e) or "InternalServerError" in str(e):
60
- time.sleep(delay * 2) # サーバーエラーの場合は長めに待機
61
- else:
62
- time.sleep(delay)
63
- continue
64
- else:
65
- print(f"最大リトライ回数に達しました: {e}")
66
- raise e
67
- return None
68
- return wrapper
69
- return decorator
70
-
71
- ## Cancer Name の抽出
72
  class ExtractTumorName(BaseModel):
73
  """Extract tumor name from the user's question."""
74
  tumor_name: str = Field(description="Extracted tumor name from the question, or 'None' if no tumor found")
@@ -76,12 +38,16 @@ class ExtractTumorName(BaseModel):
76
  class TumorNameExtractor:
77
  def __init__(self, llm):
78
  self.llm = llm
 
 
79
  self.structured_llm_extractor = self.llm.with_structured_output(ExtractTumorName)
80
 
81
- self.system_prompt = """あなたは、ユーザーの質問に基づいて腫瘍名を英語で抽出するシステムです。
82
- 質問文に腫瘍の種類や名前が含まれている場合、それを英語で返してください。
83
- 質問文に腫瘍名がない場合は 'None' と返答してください。"""
 
84
 
 
85
  self.grade_prompt = ChatPromptTemplate.from_messages(
86
  [
87
  ("system", self.system_prompt),
@@ -89,18 +55,20 @@ class TumorNameExtractor:
89
  ]
90
  )
91
 
92
- @retry_on_error(max_retries=3, delay=2)
93
  def extract_tumor_name(self, question: str) -> str:
94
- """腫瘍名を抽出するメソッド"""
95
- try:
96
- tumor_extractor = self.grade_prompt | self.structured_llm_extractor
97
- result = tumor_extractor.invoke({"question": question})
98
- return result.tumor_name
99
- except Exception as e:
100
- print(f"腫瘍名抽出エラー: {e}")
101
- return "None"
102
-
 
103
  ### 質問変更システム
 
 
104
  class ModifyQuestion(BaseModel):
105
  """Class for modifying a question by inserting NCTID."""
106
  modified_question: str = Field(description="The modified question with the inserted NCTID.")
@@ -108,15 +76,18 @@ class ModifyQuestion(BaseModel):
108
  class QuestionModifier:
109
  def __init__(self, llm):
110
  self.llm = llm
 
 
111
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
112
 
113
- # 修正: 中括弧をエスケープ
114
- self.system_prompt = """あなたは、ユーザーの質問に対して適切なNCTIDを挿入して質問を変更するシステムです。
115
- 質問文にNCTIDを挿入し、形式に基づいて新しい質問を生成してください。
116
- 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては
117
- 16歳男性の神経膠腫の患者さんは{{nct_id}}に参加できますか?と変更して下さい
118
- NCTIDは {{nct_id}} を使用してください。"""
119
 
 
120
  self.modify_prompt = ChatPromptTemplate.from_messages(
121
  [
122
  ("system", self.system_prompt),
@@ -124,27 +95,34 @@ NCTIDは {{nct_id}} を使用してください。"""
124
  ]
125
  )
126
 
127
- @retry_on_error(max_retries=3, delay=2)
128
  def modify_question(self, question: str, nct_id: str) -> str:
129
- """質問を変更するメソッド"""
130
- try:
131
- question_modifier = self.modify_prompt | self.structured_llm_modifier
132
- result = question_modifier.invoke({"question": question, "nct_id": nct_id})
133
- return result.modified_question
134
- except Exception as e:
135
- print(f"質問変更エラー: {e}")
136
- return f"{question} (NCTID: {nct_id})"
 
 
 
137
 
138
  class QuestionModifierSecond:
139
  def __init__(self, llm):
140
  self.llm = llm
 
 
141
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
142
 
143
- self.system_prompt = """あなたは、ユーザーの質問を変更するシステムです。
144
- 形式に基づいて新しい質問を生成してください。
145
- 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては
146
- 16歳男性の神経膠腫の患者さんはこの治験に参加できますか?と変更して下さい"""
 
 
147
 
 
148
  self.modify_prompt = ChatPromptTemplate.from_messages(
149
  [
150
  ("system", self.system_prompt),
@@ -152,27 +130,34 @@ class QuestionModifierSecond:
152
  ]
153
  )
154
 
155
- @retry_on_error(max_retries=3, delay=2)
156
  def modify_question(self, question: str) -> str:
157
- """質問を変更するメソッド"""
158
- try:
159
- question_modifier = self.modify_prompt | self.structured_llm_modifier
160
- result = question_modifier.invoke({"question": question})
161
- return result.modified_question
162
- except Exception as e:
163
- print(f"質問変更エラー: {e}")
164
- return question
165
-
 
 
 
166
  class QuestionModifierEnglish:
167
  def __init__(self, llm):
168
  self.llm = llm
 
 
169
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
170
 
171
- self.system_prompt = """あなたは、ユーザーの質問を変更し英語に翻訳するシステムです。
172
- 形式に基づいて新しい質問を生成してください。
173
- 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては
174
- Can a 16 year old male patient with glioma participate in this clinical trial?と変更して下さい"""
 
 
175
 
 
176
  self.modify_prompt = ChatPromptTemplate.from_messages(
177
  [
178
  ("system", self.system_prompt),
@@ -180,34 +165,41 @@ Can a 16 year old male patient with glioma participate in this clinical trial?
180
  ]
181
  )
182
 
183
- @retry_on_error(max_retries=3, delay=2)
184
  def modify_question(self, question: str) -> str:
185
- """質問を変更するメソッド"""
186
- try:
187
- question_modifier = self.modify_prompt | self.structured_llm_modifier
188
- result = question_modifier.invoke({"question": question})
189
- return result.modified_question
190
- except Exception as e:
191
- print(f"英語質問変更エラー: {e}")
192
- return question
 
 
 
 
 
 
193
 
194
- ### Make criteria check Agent
195
  class ClinicalTrialAgent:
196
  def __init__(self, llm, db):
197
  self.llm = llm
198
  self.db = db
199
 
 
200
  self.system_prompt = """
201
  あなたは患者さんに適した治験を探すエージェントです。
202
  データベースのEligibility Criteriaをチェックして患者さんがその治験を受けることが可能かどうか答えて下さい
203
  """
204
 
 
205
  self.prompt = ChatPromptTemplate.from_messages(
206
  [("system", self.system_prompt),
207
  ("human", "{input}"),
208
  MessagesPlaceholder("agent_scratchpad")]
209
  )
210
 
 
211
  self.agent_executor = self.create_sql_agent(self.llm, self.db, self.prompt)
212
 
213
  def create_sql_agent(self, llm, db, prompt):
@@ -221,56 +213,59 @@ class ClinicalTrialAgent:
221
  )
222
  return agent_executor
223
 
224
- @retry_on_error(max_retries=3, delay=2)
225
  def get_agent_judgment(self, modify_question: str) -> str:
226
- """Modifyされた質問を元に、患者さんが治験に参加可能かどうかのエージェント判断を取得"""
227
- try:
228
- result = self.agent_executor.invoke({"input": modify_question})
229
- return result
230
- except Exception as e:
231
- print(f"エージェント判断エラー: {e}")
232
- return f"エラー: {str(e)}"
 
 
233
 
234
  class SimpleClinicalTrialAgent:
235
  def __init__(self, llm):
236
  self.llm = llm
237
 
238
- @retry_on_error(max_retries=3, delay=2)
239
  def evaluate_eligibility(self, TargetCriteria: str, question: str) -> str:
240
- """臨床試験の参加適格性を評価するメソッド"""
241
- try:
242
- # 修正: プロンプト内の中括弧を適切にエスケープ
243
- prompt_template = """
244
- You are an agent looking for a suitable clinical trial for a patient.
245
- Please answer whether the patient is eligible for this clinical trial based on the following criteria. If you do not know the answer, say you do not know. Your answer should be brief, no more than 3 sentences.
246
-
247
- Question: {{question}}
248
-
249
- Criteria:
250
- {criteria}""".format(criteria=TargetCriteria)
251
-
252
- criteria_prompt = ChatPromptTemplate.from_messages(
253
- [
254
- (
255
- "human",
256
- prompt_template
257
- )
258
- ]
259
- )
260
-
261
- rag_chain = (
262
- {"question": RunnablePassthrough()}
263
- | criteria_prompt
264
- | self.llm
265
- | StrOutputParser()
266
- )
267
-
268
- response = rag_chain.invoke(question)
269
- return response
270
-
271
- except Exception as e:
272
- print(f"適格性評価エラー: {e}")
273
- return f"評価エラー: {str(e)}"
 
 
 
274
 
275
  ### output 評価システム
276
  class TrialEligibilityGrader(BaseModel):
@@ -282,14 +277,18 @@ class TrialEligibilityGrader(BaseModel):
282
  class GraderAgent:
283
  def __init__(self, llm):
284
  self.llm = llm
 
 
285
  self.structured_llm_grader = self.llm.with_structured_output(TrialEligibilityGrader)
286
 
 
287
  self.system_prompt = """
288
  あなたは治験に参加する患者の適合性を評価するGraderです。
289
  以下のドキュメントを読み、患者が治験に参加可能かどうかを判断してください。
290
  'yes'(参加可能)、'no'(参加不可能)、'unclear'(判断できない)の3値で答えてください。
291
  """
292
 
 
293
  self.grade_prompt = ChatPromptTemplate.from_messages(
294
  [
295
  ("system", self.system_prompt),
@@ -300,31 +299,34 @@ class GraderAgent:
300
  ]
301
  )
302
 
303
- @retry_on_error(max_retries=3, delay=2)
304
  def evaluate_eligibility(self, AgentJudgment_output: str) -> str:
305
- """AgentJudgment['output']を基に患者が治験に参加可能かどうかを評価し、スコア(AgentGrade)を返す"""
306
- try:
307
- GraderAgent = self.grade_prompt | self.structured_llm_grader
308
- result = GraderAgent.invoke({"document": AgentJudgment_output})
309
- return result.score
310
- except Exception as e:
311
- print(f"グレード評価エラー: {e}")
312
- return "unclear"
 
 
 
313
 
314
  class LLMTranslator:
315
  def __init__(self, llm):
316
  self.llm = llm
317
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
318
 
319
- self.system_prompt = """あなたは、優秀な翻訳者です。
320
- 日本語を英語に翻訳して下さい。"""
321
-
322
- self.system_prompt2 = """あなたは、優秀な翻訳者です。
323
- 日本語を英語に以下のフォーマットに従って翻訳して下さい。
324
- MainQuestion:
325
- Known gene mutation:
326
- Measurable tumour:
327
- Biopsiable tumour:"""
 
328
 
329
  self.modify_prompt = ChatPromptTemplate.from_messages(
330
  [
@@ -341,123 +343,81 @@ Biopsiable tumour:"""
341
  )
342
 
343
  def is_english(self, text: str) -> bool:
344
- """簡易的にテキストが英語かどうかを判定する関数"""
 
 
 
 
 
345
  return bool(re.match(r'^[A-Za-z0-9\s.,?!]+$', text))
346
 
347
- @retry_on_error(max_retries=3, delay=2)
348
  def translate(self, question: str) -> str:
349
- """質問を翻訳するメソッド。英語の質問はそのまま返す。"""
350
- try:
351
- if self.is_english(question):
352
- return question
353
-
354
- question_modifier = self.modify_prompt | self.structured_llm_modifier
355
- result = question_modifier.invoke({"question": question})
356
- return result.modified_question
357
- except Exception as e:
358
- print(f"翻訳エラー: {e}")
359
  return question
360
-
361
- @retry_on_error(max_retries=3, delay=2)
 
 
 
 
 
362
  def translateQuestion(self, question: str) -> str:
363
- """フォーマット付きで質問を翻訳するメソッド"""
364
- try:
365
- question_modifier = self.modify_prompt2 | self.structured_llm_modifier
366
- result = question_modifier.invoke({"question": question})
367
- return result.modified_question
368
- except Exception as e:
369
- print(f"フォーマット翻訳エラー: {e}")
370
- return question
 
371
 
372
  def generate_ex_question(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
373
- """日本語での質問文を生成"""
374
- try:
375
- # GeneMutationが空の場合はUnknownに設定
376
- gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
377
-
378
- # MeseableとBiopsiableの値をYes, No, Unknownに変換
379
- meseable_text = (
380
- "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
381
- )
382
- biopsiable_text = (
383
- "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
384
- )
385
-
386
- # 質問文の生成
387
- ex_question = f"""{age}歳{sex}の{tumor_type}患者さんはこの治験に参加することができますか?
388
  判明している遺伝子変異: {gene_mutation_text}
389
  Meseable tumor: {meseable_text}
390
  Biopsiable tumor: {biopsiable_text}
391
- です。"""
392
- return ex_question
393
- except Exception as e:
394
- print(f"日本語質問生成エラー: {e}")
395
- return f"{age}歳{sex}の{tumor_type}患者さんの治験参加について"
396
 
397
  def generate_ex_question_English(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
398
- """英語での質問文を生成"""
399
- try:
400
- # GeneMutationが空の場合は"Unknown"に設定
401
- gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
402
-
403
- # sexの値を male または female に変換
404
- sex_text = "male" if sex == "男性" else "female" if sex == "女性" else "Unknown"
405
-
406
- # MeseableとBiopsiableの値を "Yes", "No", "Unknown" に変換
407
- meseable_text = (
408
- "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
409
- )
410
- biopsiable_text = (
411
- "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
412
- )
413
-
414
- # 英語での質問文を生成
415
- ex_question = f"""Can a {age}-year-old {sex_text} patient with {tumor_type} participate in this clinical trial?
416
  Known gene mutation: {gene_mutation_text}
417
  Measurable tumor: {meseable_text}
418
- Biopsiable tumor: {biopsiable_text}"""
419
- return ex_question
420
- except Exception as e:
421
- print(f"英語質問生成エラー: {e}")
422
- return f"Can a {age}-year-old patient with {tumor_type} participate in this clinical trial?"
423
-
424
- # テスト関数
425
- def test_clinical_trial_tools():
426
- """臨床試験ツールのテスト関数"""
427
- try:
428
- from langchain_groq import ChatGroq
429
-
430
- # Groqクライアントの初期化
431
- groq = ChatGroq(model_name="llama3-70b-8192", temperature=0)
432
-
433
- # 各エージェントの初期化テスト
434
- translator = LLMTranslator(groq)
435
- criteria_agent = SimpleClinicalTrialAgent(groq)
436
- grader_agent = GraderAgent(groq)
437
-
438
- print("✅ 全てのエージェントが正常に初期化されました")
439
-
440
- # サンプル質問の生成テスト
441
- sample_question = generate_ex_question_English(
442
- age="45",
443
- sex="女性",
444
- tumor_type="breast cancer",
445
- GeneMutation="HER2",
446
- Meseable="有り",
447
- Biopsiable="有り"
448
- )
449
-
450
- print(f"✅ サンプル質問生成成功: {sample_question}")
451
- return True
452
-
453
- except Exception as e:
454
- print(f"❌ テスト中にエラーが発生しました: {e}")
455
- return False
456
-
457
- if __name__ == "__main__":
458
- print("ClinicalTrialTools のテストを開始します...")
459
- success = test_clinical_trial_tools()
460
- if success:
461
- print("✅ テストが正常に完了しました。")
462
- else:
463
- print("❌ テストでエラーが発生しました。")
 
2
  from langchain_openai import ChatOpenAI
3
  from langchain_groq import ChatGroq
4
  from langchain_core.prompts import ChatPromptTemplate
5
+ from langchain_core.pydantic_v1 import BaseModel, Field
 
 
 
 
 
6
  import pandas as pd
7
+ from pydantic import BaseModel, Field
 
 
8
 
9
  from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  from langchain_community.vectorstores import Chroma
11
+ from langchain.embeddings import HuggingFaceEmbeddings
 
 
 
 
 
12
  from langchain_core.runnables import RunnablePassthrough
13
  from langchain_core.output_parsers import StrOutputParser
14
 
 
 
15
 
16
+
17
+ gpt = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
18
+ #agent_gpt_executor = create_sql_agent(gpt, db=db, agent_type="tool-calling", verbose=True)
19
+
20
+ ## make database
21
  from langchain_community.utilities import SQLDatabase
22
  from sqlalchemy import create_engine
23
+
24
  from langchain.prompts import ChatPromptTemplate
25
  from langchain.schema import SystemMessage
26
  from langchain_core.prompts import MessagesPlaceholder
27
+ #agent_groq_executor = create_sql_agent(llm, db=db, agent_type="tool-calling", verbose=True)
28
 
29
  from OpenAITools.FetchTools import fetch_clinical_trials, fetch_clinical_trials_jp
30
 
31
+
32
+
33
+ ## Cancer Name の抽出
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  class ExtractTumorName(BaseModel):
35
  """Extract tumor name from the user's question."""
36
  tumor_name: str = Field(description="Extracted tumor name from the question, or 'None' if no tumor found")
 
38
  class TumorNameExtractor:
39
  def __init__(self, llm):
40
  self.llm = llm
41
+
42
+ # LLMの出力を構造化するための設定
43
  self.structured_llm_extractor = self.llm.with_structured_output(ExtractTumorName)
44
 
45
+ # システムプロンプトを設定
46
+ self.system_prompt = """あなたは、ユーザーの質問に基づいて腫瘍名を英語で抽出するシステムです。\n
47
+ 質問文に腫瘍の種類や名前が含まれている場合、それを英語で返してください。\n
48
+ 質問文に腫瘍名がない場合は 'None' と返答してください。"""
49
 
50
+ # プロンプトテンプレート
51
  self.grade_prompt = ChatPromptTemplate.from_messages(
52
  [
53
  ("system", self.system_prompt),
 
55
  ]
56
  )
57
 
 
58
  def extract_tumor_name(self, question: str) -> str:
59
+ """
60
+ 腫瘍名を抽出するメソッド。
61
+ :param question: 質問文
62
+ :return: 抽出された腫瘍名
63
+ """
64
+ # 質問から腫瘍名を抽出する処理
65
+ tumor_extractor = self.grade_prompt | self.structured_llm_extractor
66
+ result = tumor_extractor.invoke({"question": question})
67
+ return result.tumor_name
68
+
69
  ### 質問変更システム
70
+
71
+ # ModifyQuestionの出力形式を定義
72
  class ModifyQuestion(BaseModel):
73
  """Class for modifying a question by inserting NCTID."""
74
  modified_question: str = Field(description="The modified question with the inserted NCTID.")
 
76
  class QuestionModifier:
77
  def __init__(self, llm):
78
  self.llm = llm
79
+
80
+ # LLMの出力を構造化するための設定
81
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
82
 
83
+ # システムプロンプトを設定
84
+ self.system_prompt = """あなたは、ユーザーの質問に対して適切なNCTIDを挿入して質問を変更するシステムです。\n
85
+ 質問文にNCTIDを挿入し、形式に基づいて新しい質問を生成してください。\n
86
+ 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては\n
87
+ 16歳男性の神経膠腫の患者さんは{nct_id}に参加できますか?と変更して下さい\n
88
+ NCTIDは {nct_id} を使用してください。"""
89
 
90
+ # プロンプトテンプレート
91
  self.modify_prompt = ChatPromptTemplate.from_messages(
92
  [
93
  ("system", self.system_prompt),
 
95
  ]
96
  )
97
 
 
98
  def modify_question(self, question: str, nct_id: str) -> str:
99
+ """
100
+ 質問を変更するメソッド。
101
+ :param question: 質問文
102
+ :param nct_id: NCTID
103
+ :return: NCTIDを挿入した新しい質問
104
+ """
105
+ # 質問を変更するプロセス
106
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
107
+ result = question_modifier.invoke({"question": question, "nct_id": nct_id})
108
+ modify_question = result.modified_question
109
+ return modify_question
110
 
111
  class QuestionModifierSecond:
112
  def __init__(self, llm):
113
  self.llm = llm
114
+
115
+ # LLMの出力を構造化するための設定
116
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
117
 
118
+ # システムプロンプトを設定
119
+ self.system_prompt = """あなたは、ユーザーの質問を変更するシステムです。\n
120
+ 形式に基づいて新しい質問を生成してください。\n
121
+ 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては\n
122
+ 16歳男性の神経膠腫の患者さんはlこの治験に参加できますか?と変更して下さい\n
123
+ """
124
 
125
+ # プロンプトテンプレート
126
  self.modify_prompt = ChatPromptTemplate.from_messages(
127
  [
128
  ("system", self.system_prompt),
 
130
  ]
131
  )
132
 
 
133
  def modify_question(self, question: str) -> str:
134
+ """
135
+ 質問を変更するメソッド。
136
+ :param question: 質問文
137
+ :param nct_id: NCTID
138
+ :return: NCTIDを挿入した新しい質問
139
+ """
140
+ # 質問を変更するプロセス
141
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
142
+ result = question_modifier.invoke({"question": question})
143
+ modify_question = result.modified_question
144
+ return modify_question
145
+
146
  class QuestionModifierEnglish:
147
  def __init__(self, llm):
148
  self.llm = llm
149
+
150
+ # LLMの出力を構造化するための設定
151
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
152
 
153
+ # システムプロンプトを設定
154
+ self.system_prompt = """あなたは、ユーザーの質問を変更し英語に翻訳するシステムです。\n
155
+ 形式に基づいて新しい質問を生成してください。\n
156
+ 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては\n
157
+ Can a 16 year old male patient with glioma participate in this clinical trial?と変更して下さい\n
158
+ """
159
 
160
+ # プロンプトテンプレート
161
  self.modify_prompt = ChatPromptTemplate.from_messages(
162
  [
163
  ("system", self.system_prompt),
 
165
  ]
166
  )
167
 
 
168
  def modify_question(self, question: str) -> str:
169
+ """
170
+ 質問を変更するメソッド。
171
+ :param question: 質問文
172
+ :param nct_id: NCTID
173
+ :return: NCTIDを挿入した新しい質問
174
+ """
175
+ # 質問を変更するプロセス
176
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
177
+ result = question_modifier.invoke({"question": question})
178
+ modify_question = result.modified_question
179
+ return modify_question
180
+
181
+
182
+ ### Make criteria check Agent
183
 
 
184
  class ClinicalTrialAgent:
185
  def __init__(self, llm, db):
186
  self.llm = llm
187
  self.db = db
188
 
189
+ # システムプロンプトの定義
190
  self.system_prompt = """
191
  あなたは患者さんに適した治験を探すエージェントです。
192
  データベースのEligibility Criteriaをチェックして患者さんがその治験を受けることが可能かどうか答えて下さい
193
  """
194
 
195
+ # プロンプトテンプレートを作成
196
  self.prompt = ChatPromptTemplate.from_messages(
197
  [("system", self.system_prompt),
198
  ("human", "{input}"),
199
  MessagesPlaceholder("agent_scratchpad")]
200
  )
201
 
202
+ # SQL Agentの設定
203
  self.agent_executor = self.create_sql_agent(self.llm, self.db, self.prompt)
204
 
205
  def create_sql_agent(self, llm, db, prompt):
 
213
  )
214
  return agent_executor
215
 
 
216
  def get_agent_judgment(self, modify_question: str) -> str:
217
+ """
218
+ Modify���れた質問を元に、患者さんが治験に参加可能かどうかのエージェント判断を取得。
219
+ :param modify_question: NCTIDが挿入された質問
220
+ :return: エージェントの判断 (AgentJudgment)
221
+ """
222
+ # LLMに質問を投げて、判断を得る
223
+ result = self.agent_executor.invoke({"input": modify_question})
224
+ return result
225
+
226
 
227
  class SimpleClinicalTrialAgent:
228
  def __init__(self, llm):
229
  self.llm = llm
230
 
 
231
  def evaluate_eligibility(self, TargetCriteria: str, question: str) -> str:
232
+ """
233
+ 臨床試験の参加適格性を評価するメソッド。
234
+ :param TargetCriteria: 試験基準 (Inclusion/Exclusion criteria)
235
+ :param question: 患者の条件に関する質問
236
+ :return: 臨床試験に参加可能かどうかのLLMからの応答
237
+ """
238
+
239
+ # プロンプトの定義
240
+ prompt_template = """
241
+ You are an agent looking for a suitable clinical trial for a patient.
242
+ Please answer whether the patient is eligible for this clinical trial based on the following criteria. If you do not know the answer, say you do not know. Your answer should be brief, no more than 3 sentences.
243
+ Question: {question}
244
+ Criteria:
245
+ """ + TargetCriteria
246
+
247
+ # プロンプトテンプレートの作成
248
+ criteria_prompt = ChatPromptTemplate.from_messages(
249
+ [
250
+ (
251
+ "human",
252
+ prompt_template
253
+ )
254
+ ]
255
+ )
256
+
257
+ # RAGチェーンの作成
258
+ rag_chain = (
259
+ {"question": RunnablePassthrough()}
260
+ | criteria_prompt
261
+ | self.llm
262
+ | StrOutputParser()
263
+ )
264
+
265
+ # 質問をチェーンに渡して、応答を得る
266
+ response = rag_chain.invoke(question)
267
+ return response
268
+
269
 
270
  ### output 評価システム
271
  class TrialEligibilityGrader(BaseModel):
 
277
  class GraderAgent:
278
  def __init__(self, llm):
279
  self.llm = llm
280
+
281
+ # LLMの出力を構造化するための設定
282
  self.structured_llm_grader = self.llm.with_structured_output(TrialEligibilityGrader)
283
 
284
+ # Graderの入力プロンプト
285
  self.system_prompt = """
286
  あなたは治験に参加する患者の適合性を評価するGraderです。
287
  以下のドキュメントを読み、患者が治験に参加可能かどうかを判断してください。
288
  'yes'(参加可能)、'no'(参加不可能)、'unclear'(判断できない)の3値で答えてください。
289
  """
290
 
291
+ # 評価のためのプロンプトを作成
292
  self.grade_prompt = ChatPromptTemplate.from_messages(
293
  [
294
  ("system", self.system_prompt),
 
299
  ]
300
  )
301
 
 
302
  def evaluate_eligibility(self, AgentJudgment_output: str) -> str:
303
+ """
304
+ AgentJudgment['output']を基に患者が治験に参加可能かどうかを評価し、スコア(AgentGrade)を返す。
305
+ :param AgentJudgment_output: エージェント判断の 'output' の値
306
+ :return: 評価されたスコア (AgentGrade)
307
+ """
308
+ GraderAgent = self.grade_prompt | self.structured_llm_grader
309
+ result = GraderAgent.invoke({"document": AgentJudgment_output})
310
+ AgentGrade = result.score
311
+ return AgentGrade
312
+
313
+ import re
314
 
315
  class LLMTranslator:
316
  def __init__(self, llm):
317
  self.llm = llm
318
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
319
 
320
+ self.system_prompt = """あなたは、優秀な翻訳者です。\n
321
+ 日本語を英語に翻訳して下さい。\n
322
+ """
323
+ self.system_prompt2 = """あなたは、優秀な翻訳者です。\n
324
+ 日本語を英語に以下のフォーマットに従って翻訳して下さい。\n
325
+ MainQuestion:
326
+ Known gene mutation:
327
+ Measurable tumour:
328
+ Biopsiable tumour:
329
+ """
330
 
331
  self.modify_prompt = ChatPromptTemplate.from_messages(
332
  [
 
343
  )
344
 
345
  def is_english(self, text: str) -> bool:
346
+ """
347
+ 簡易的にテキストが英語かどうかを判定する関数
348
+ :param text: 判定するテキスト
349
+ :return: 英語の場合True、日本語の場合False
350
+ """
351
+ # 英語のアルファベットが多く含まれているかを確認
352
  return bool(re.match(r'^[A-Za-z0-9\s.,?!]+$', text))
353
 
 
354
  def translate(self, question: str) -> str:
355
+ """
356
+ 質問を翻訳するメソッド。英語の質問はそのまま返す。
357
+ :param question: 質問文
358
+ :return: 翻訳済みの質問文、または元の質問文(英語の場合)
359
+ """
360
+ # 質問が英語の場合、そのまま返す
361
+ if self.is_english(question):
 
 
 
362
  return question
363
+
364
+ # 日本語の質問は翻訳プロセスにかける
365
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
366
+ result = question_modifier.invoke({"question": question})
367
+ modify_question = result.modified_question
368
+ return modify_question
369
+
370
  def translateQuestion(self, question: str) -> str:
371
+ """
372
+ フォーマット付きで質問を翻訳するメソッド。
373
+ :param question: 質問文
374
+ :return: フォーマットに従った翻訳済みの質問
375
+ """
376
+ question_modifier = self.modify_prompt2 | self.structured_llm_modifier
377
+ result = question_modifier.invoke({"question": question})
378
+ modify_question = result.modified_question
379
+ return modify_question
380
 
381
  def generate_ex_question(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
382
+ # GeneMutationが空の場合はUnknownに設定
383
+ gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
384
+
385
+ # MeseableとBiopsiableの値をYes, No, Unknownに変換
386
+ meseable_text = (
387
+ "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
388
+ )
389
+ biopsiable_text = (
390
+ "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
391
+ )
392
+
393
+ # 質問文の生成
394
+ ex_question = f"""{age}歳{sex}の{tumor_type}患者さんはこの治験に参加することができますか?
 
 
395
  判明している遺伝子変異: {gene_mutation_text}
396
  Meseable tumor: {meseable_text}
397
  Biopsiable tumor: {biopsiable_text}
398
+ です。
399
+ """
400
+ return ex_question
 
 
401
 
402
  def generate_ex_question_English(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
403
+ # GeneMutationが空の場合は"Unknown"に設定
404
+ gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
405
+
406
+ # sexの値を male または female に変換
407
+ sex_text = "male" if sex == "男性" else "female" if sex == "女性" else "Unknown"
408
+
409
+ # MeseableとBiopsiableの値を "Yes", "No", "Unknown" に変換
410
+ meseable_text = (
411
+ "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
412
+ )
413
+ biopsiable_text = (
414
+ "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
415
+ )
416
+
417
+ # 英語での質問文を生成
418
+ ex_question = f"""Can a {age}-year-old {sex_text} patient with {tumor_type} participate in this clinical trial?
 
 
419
  Known gene mutation: {gene_mutation_text}
420
  Measurable tumor: {meseable_text}
421
+ Biopsiable tumor: {biopsiable_text}
422
+ """
423
+ return ex_question
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
OpenAITools/{CrinicalTrialTools_old.py → CrinicalTrialTools_new.py} RENAMED
@@ -2,35 +2,73 @@ from langchain_community.agent_toolkits import create_sql_agent
2
  from langchain_openai import ChatOpenAI
3
  from langchain_groq import ChatGroq
4
  from langchain_core.prompts import ChatPromptTemplate
5
- from langchain_core.pydantic_v1 import BaseModel, Field
 
 
 
 
 
6
  import pandas as pd
7
- from pydantic import BaseModel, Field
 
 
8
 
9
  from langchain.text_splitter import RecursiveCharacterTextSplitter
10
  from langchain_community.vectorstores import Chroma
11
- from langchain.embeddings import HuggingFaceEmbeddings
 
 
 
 
 
12
  from langchain_core.runnables import RunnablePassthrough
13
  from langchain_core.output_parsers import StrOutputParser
14
 
 
 
15
 
16
-
17
- gpt = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
18
- #agent_gpt_executor = create_sql_agent(gpt, db=db, agent_type="tool-calling", verbose=True)
19
-
20
- ## make database
21
  from langchain_community.utilities import SQLDatabase
22
  from sqlalchemy import create_engine
23
-
24
  from langchain.prompts import ChatPromptTemplate
25
  from langchain.schema import SystemMessage
26
  from langchain_core.prompts import MessagesPlaceholder
27
- #agent_groq_executor = create_sql_agent(llm, db=db, agent_type="tool-calling", verbose=True)
28
 
29
  from OpenAITools.FetchTools import fetch_clinical_trials, fetch_clinical_trials_jp
30
 
31
-
32
-
33
- ## Cancer Name の抽出
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  class ExtractTumorName(BaseModel):
35
  """Extract tumor name from the user's question."""
36
  tumor_name: str = Field(description="Extracted tumor name from the question, or 'None' if no tumor found")
@@ -38,16 +76,12 @@ class ExtractTumorName(BaseModel):
38
  class TumorNameExtractor:
39
  def __init__(self, llm):
40
  self.llm = llm
41
-
42
- # LLMの出力を構造化するための設定
43
  self.structured_llm_extractor = self.llm.with_structured_output(ExtractTumorName)
44
 
45
- # システムプロンプトを設定
46
- self.system_prompt = """あなたは、ユーザーの質問に基づいて腫瘍名を英語で抽出するシステムです。\n
47
- 質問文に腫瘍の種類や名前が含まれている場合、それを英語で返してください。\n
48
- 質問文に腫瘍名がない場合は 'None' と返答してください。"""
49
 
50
- # プロンプトテンプレート
51
  self.grade_prompt = ChatPromptTemplate.from_messages(
52
  [
53
  ("system", self.system_prompt),
@@ -55,20 +89,18 @@ class TumorNameExtractor:
55
  ]
56
  )
57
 
 
58
  def extract_tumor_name(self, question: str) -> str:
59
- """
60
- 腫瘍名を抽出するメソッド。
61
- :param question: 質問文
62
- :return: 抽出された腫瘍名
63
- """
64
- # 質問から腫瘍名を抽出する処理
65
- tumor_extractor = self.grade_prompt | self.structured_llm_extractor
66
- result = tumor_extractor.invoke({"question": question})
67
- return result.tumor_name
68
-
69
- ### 質問変更システム
70
 
71
- # ModifyQuestionの出力形式を定義
72
  class ModifyQuestion(BaseModel):
73
  """Class for modifying a question by inserting NCTID."""
74
  modified_question: str = Field(description="The modified question with the inserted NCTID.")
@@ -76,18 +108,15 @@ class ModifyQuestion(BaseModel):
76
  class QuestionModifier:
77
  def __init__(self, llm):
78
  self.llm = llm
79
-
80
- # LLMの出力を構造化するための設定
81
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
82
 
83
- # システムプロンプトを設定
84
- self.system_prompt = """あなたは、ユーザーの質問に対して適切なNCTIDを挿入して質問を変更するシステムです。\n
85
- 質問文にNCTIDを挿入し、形式に基づいて新しい質問を生成してください。\n
86
- 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては\n
87
- 16歳男性の神経膠腫の患者さんは{nct_id}に参加できますか?と変更して下さい\n
88
- NCTIDは {nct_id} を使用してください。"""
89
 
90
- # プロンプトテンプレート
91
  self.modify_prompt = ChatPromptTemplate.from_messages(
92
  [
93
  ("system", self.system_prompt),
@@ -95,34 +124,27 @@ class QuestionModifier:
95
  ]
96
  )
97
 
 
98
  def modify_question(self, question: str, nct_id: str) -> str:
99
- """
100
- 質問を変更するメソッド。
101
- :param question: 質問文
102
- :param nct_id: NCTID
103
- :return: NCTIDを挿入した新しい質問
104
- """
105
- # 質問を変更するプロセス
106
- question_modifier = self.modify_prompt | self.structured_llm_modifier
107
- result = question_modifier.invoke({"question": question, "nct_id": nct_id})
108
- modify_question = result.modified_question
109
- return modify_question
110
 
111
  class QuestionModifierSecond:
112
  def __init__(self, llm):
113
  self.llm = llm
114
-
115
- # LLMの出力を構造化するための設定
116
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
117
 
118
- # システムプロンプトを設定
119
- self.system_prompt = """あなたは、ユーザーの質問を変更するシステムです。\n
120
- 形式に基づいて新しい質問を生成してください。\n
121
- 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては\n
122
- 16歳男性の神経膠腫の患者さんはlこの治験に参加できますか?と変更して下さい\n
123
- """
124
 
125
- # プロンプトテンプレート
126
  self.modify_prompt = ChatPromptTemplate.from_messages(
127
  [
128
  ("system", self.system_prompt),
@@ -130,34 +152,27 @@ class QuestionModifierSecond:
130
  ]
131
  )
132
 
 
133
  def modify_question(self, question: str) -> str:
134
- """
135
- 質問を変更するメソッド。
136
- :param question: 質問文
137
- :param nct_id: NCTID
138
- :return: NCTIDを挿入した新しい質問
139
- """
140
- # 質問を変更するプロセス
141
- question_modifier = self.modify_prompt | self.structured_llm_modifier
142
- result = question_modifier.invoke({"question": question})
143
- modify_question = result.modified_question
144
- return modify_question
145
-
146
  class QuestionModifierEnglish:
147
  def __init__(self, llm):
148
  self.llm = llm
149
-
150
- # LLMの出力を構造化するための設定
151
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
152
 
153
- # システムプロンプトを設定
154
- self.system_prompt = """あなたは、ユーザーの質問を変更し英語に翻訳するシステムです。\n
155
- 形式に基づいて新しい質問を生成してください。\n
156
- 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては\n
157
- Can a 16 year old male patient with glioma participate in this clinical trial?と変更して下さい\n
158
- """
159
 
160
- # プロンプトテンプレート
161
  self.modify_prompt = ChatPromptTemplate.from_messages(
162
  [
163
  ("system", self.system_prompt),
@@ -165,41 +180,34 @@ class QuestionModifierEnglish:
165
  ]
166
  )
167
 
 
168
  def modify_question(self, question: str) -> str:
169
- """
170
- 質問を変更するメソッド。
171
- :param question: 質問文
172
- :param nct_id: NCTID
173
- :return: NCTIDを挿入した新しい質問
174
- """
175
- # 質問を変更するプロセス
176
- question_modifier = self.modify_prompt | self.structured_llm_modifier
177
- result = question_modifier.invoke({"question": question})
178
- modify_question = result.modified_question
179
- return modify_question
180
-
181
-
182
- ### Make criteria check Agent
183
 
 
184
  class ClinicalTrialAgent:
185
  def __init__(self, llm, db):
186
  self.llm = llm
187
  self.db = db
188
 
189
- # システムプロンプトの定義
190
  self.system_prompt = """
191
  あなたは患者さんに適した治験を探すエージェントです。
192
  データベースのEligibility Criteriaをチェックして患者さんがその治験を受けることが可能かどうか答えて下さい
193
  """
194
 
195
- # プロンプトテンプレートを作成
196
  self.prompt = ChatPromptTemplate.from_messages(
197
  [("system", self.system_prompt),
198
  ("human", "{input}"),
199
  MessagesPlaceholder("agent_scratchpad")]
200
  )
201
 
202
- # SQL Agentの設定
203
  self.agent_executor = self.create_sql_agent(self.llm, self.db, self.prompt)
204
 
205
  def create_sql_agent(self, llm, db, prompt):
@@ -213,59 +221,56 @@ class ClinicalTrialAgent:
213
  )
214
  return agent_executor
215
 
 
216
  def get_agent_judgment(self, modify_question: str) -> str:
217
- """
218
- Modifyされた質問を元に、患者さんが治験に参加可能かどうかのエージェント判断を取得。
219
- :param modify_question: NCTIDが挿入された質問
220
- :return: エージェントの判断 (AgentJudgment)
221
- """
222
- # LLMに質問を投げて、判断を得る
223
- result = self.agent_executor.invoke({"input": modify_question})
224
- return result
225
-
226
 
227
  class SimpleClinicalTrialAgent:
228
  def __init__(self, llm):
229
  self.llm = llm
230
 
 
231
  def evaluate_eligibility(self, TargetCriteria: str, question: str) -> str:
232
- """
233
- 臨床試験の参加適格性を評価するメソッド。
234
- :param TargetCriteria: 試験基準 (Inclusion/Exclusion criteria)
235
- :param question: 患者の条件に関する質問
236
- :return: 臨床試験に参加可能かどうかのLLMからの応答
237
- """
238
-
239
- # プロンプトの定義
240
- prompt_template = """
241
- You are an agent looking for a suitable clinical trial for a patient.
242
- Please answer whether the patient is eligible for this clinical trial based on the following criteria. If you do not know the answer, say you do not know. Your answer should be brief, no more than 3 sentences.
243
- Question: {question}
244
- Criteria:
245
- """ + TargetCriteria
246
-
247
- # プロンプトテンプレートの作成
248
- criteria_prompt = ChatPromptTemplate.from_messages(
249
- [
250
- (
251
- "human",
252
- prompt_template
253
- )
254
- ]
255
- )
256
-
257
- # RAGチェーンの作成
258
- rag_chain = (
259
- {"question": RunnablePassthrough()}
260
- | criteria_prompt
261
- | self.llm
262
- | StrOutputParser()
263
- )
264
-
265
- # 質問をチェーンに渡して、応答を得る
266
- response = rag_chain.invoke(question)
267
- return response
268
-
269
 
270
  ### output 評価システム
271
  class TrialEligibilityGrader(BaseModel):
@@ -277,18 +282,14 @@ class TrialEligibilityGrader(BaseModel):
277
  class GraderAgent:
278
  def __init__(self, llm):
279
  self.llm = llm
280
-
281
- # LLMの出力を構造化するための設定
282
  self.structured_llm_grader = self.llm.with_structured_output(TrialEligibilityGrader)
283
 
284
- # Graderの入力プロンプト
285
  self.system_prompt = """
286
  あなたは治験に参加する患者の適合性を評価するGraderです。
287
  以下のドキュメントを読み、患者が治験に参加可能かどうかを判断してください。
288
  'yes'(参加可能)、'no'(参加不可能)、'unclear'(判断できない)の3値で答えてください。
289
  """
290
 
291
- # 評価のためのプロンプトを作成
292
  self.grade_prompt = ChatPromptTemplate.from_messages(
293
  [
294
  ("system", self.system_prompt),
@@ -299,34 +300,31 @@ class GraderAgent:
299
  ]
300
  )
301
 
 
302
  def evaluate_eligibility(self, AgentJudgment_output: str) -> str:
303
- """
304
- AgentJudgment['output']を基に患者が治験に参加可能かどうかを評価し、スコア(AgentGrade)を返す。
305
- :param AgentJudgment_output: エージェント判断の 'output' の値
306
- :return: 評価されたスコア (AgentGrade)
307
- """
308
- GraderAgent = self.grade_prompt | self.structured_llm_grader
309
- result = GraderAgent.invoke({"document": AgentJudgment_output})
310
- AgentGrade = result.score
311
- return AgentGrade
312
-
313
- import re
314
 
315
  class LLMTranslator:
316
  def __init__(self, llm):
317
  self.llm = llm
318
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
319
 
320
- self.system_prompt = """あなたは、優秀な翻訳者です。\n
321
- 日本語を英語に翻訳して下さい。\n
322
- """
323
- self.system_prompt2 = """あなたは、優秀な翻訳者です。\n
324
- 日本語を英語に以下のフォーマットに従って翻訳して下さい。\n
325
- MainQuestion:
326
- Known gene mutation:
327
- Measurable tumour:
328
- Biopsiable tumour:
329
- """
330
 
331
  self.modify_prompt = ChatPromptTemplate.from_messages(
332
  [
@@ -343,81 +341,123 @@ class LLMTranslator:
343
  )
344
 
345
  def is_english(self, text: str) -> bool:
346
- """
347
- 簡易的にテキストが英語かどうかを判定する関数
348
- :param text: 判定するテキスト
349
- :return: 英語の場合True、日本語の場合False
350
- """
351
- # 英語のアルファベットが多く含まれているかを確認
352
  return bool(re.match(r'^[A-Za-z0-9\s.,?!]+$', text))
353
 
 
354
  def translate(self, question: str) -> str:
355
- """
356
- 質問を翻訳するメソッド。英語の質問はそのまま返す。
357
- :param question: 質問文
358
- :return: 翻訳済みの質問文、または元の質問文(英語の場合)
359
- """
360
- # 質問が英語の場合、そのまま返す
361
- if self.is_english(question):
 
 
 
362
  return question
363
-
364
- # 日本語の質問は翻訳プロセスにかける
365
- question_modifier = self.modify_prompt | self.structured_llm_modifier
366
- result = question_modifier.invoke({"question": question})
367
- modify_question = result.modified_question
368
- return modify_question
369
-
370
  def translateQuestion(self, question: str) -> str:
371
- """
372
- フォーマット付きで質問を翻訳するメソッド。
373
- :param question: 質問文
374
- :return: フォーマットに従った翻訳済みの質問
375
- """
376
- question_modifier = self.modify_prompt2 | self.structured_llm_modifier
377
- result = question_modifier.invoke({"question": question})
378
- modify_question = result.modified_question
379
- return modify_question
380
 
381
  def generate_ex_question(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
382
- # GeneMutationが空の場合はUnknownに設定
383
- gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
384
-
385
- # MeseableとBiopsiableの値をYes, No, Unknownに変換
386
- meseable_text = (
387
- "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
388
- )
389
- biopsiable_text = (
390
- "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
391
- )
392
-
393
- # 質問文の生成
394
- ex_question = f"""{age}歳{sex}の{tumor_type}患者さんはこの治験に参加することができますか?
 
 
395
  判明している遺伝子変異: {gene_mutation_text}
396
  Meseable tumor: {meseable_text}
397
  Biopsiable tumor: {biopsiable_text}
398
- です。
399
- """
400
- return ex_question
 
 
401
 
402
  def generate_ex_question_English(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
403
- # GeneMutationが空の場合は"Unknown"に設定
404
- gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
405
-
406
- # sexの値を male または female に変換
407
- sex_text = "male" if sex == "男性" else "female" if sex == "女性" else "Unknown"
408
-
409
- # MeseableとBiopsiableの値を "Yes", "No", "Unknown" に変換
410
- meseable_text = (
411
- "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
412
- )
413
- biopsiable_text = (
414
- "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
415
- )
416
-
417
- # 英語での質問文を生成
418
- ex_question = f"""Can a {age}-year-old {sex_text} patient with {tumor_type} participate in this clinical trial?
 
 
419
  Known gene mutation: {gene_mutation_text}
420
  Measurable tumor: {meseable_text}
421
- Biopsiable tumor: {biopsiable_text}
422
- """
423
- return ex_question
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
  from langchain_openai import ChatOpenAI
3
  from langchain_groq import ChatGroq
4
  from langchain_core.prompts import ChatPromptTemplate
5
+ # 修正: pydantic v1の非推奨警告を解決
6
+ try:
7
+ from pydantic import BaseModel, Field
8
+ except ImportError:
9
+ from langchain_core.pydantic_v1 import BaseModel, Field
10
+
11
  import pandas as pd
12
+ import time
13
+ import re
14
+ from typing import Optional
15
 
16
  from langchain.text_splitter import RecursiveCharacterTextSplitter
17
  from langchain_community.vectorstores import Chroma
18
+ # 修正: HuggingFaceEmbeddingsの非推奨警告を解決
19
+ try:
20
+ from langchain_community.embeddings import HuggingFaceEmbeddings
21
+ except ImportError:
22
+ from langchain.embeddings import HuggingFaceEmbeddings
23
+
24
  from langchain_core.runnables import RunnablePassthrough
25
  from langchain_core.output_parsers import StrOutputParser
26
 
27
+ # 修正: モジュールレベルでの初期化を削除
28
+ # gpt = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
29
 
30
+ ## Database関連のインポート
 
 
 
 
31
  from langchain_community.utilities import SQLDatabase
32
  from sqlalchemy import create_engine
 
33
  from langchain.prompts import ChatPromptTemplate
34
  from langchain.schema import SystemMessage
35
  from langchain_core.prompts import MessagesPlaceholder
 
36
 
37
  from OpenAITools.FetchTools import fetch_clinical_trials, fetch_clinical_trials_jp
38
 
39
+ # GPT初期化を関数として追加
40
+ def get_openai_client():
41
+ """OpenAIクライアントを安全に初期化"""
42
+ try:
43
+ return ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
44
+ except Exception as e:
45
+ print(f"OpenAI初期化エラー: {e}")
46
+ return None
47
+
48
+ # エラーハンドリング用のデコレータ
49
+ def retry_on_error(max_retries=3, delay=1):
50
+ """エラー時のリトライデコレータ"""
51
+ def decorator(func):
52
+ def wrapper(*args, **kwargs):
53
+ for attempt in range(max_retries):
54
+ try:
55
+ return func(*args, **kwargs)
56
+ except Exception as e:
57
+ if attempt < max_retries - 1:
58
+ print(f"エラーが発生しました (試行 {attempt + 1}/{max_retries}): {e}")
59
+ if "no healthy upstream" in str(e) or "InternalServerError" in str(e):
60
+ time.sleep(delay * 2) # サーバーエラーの場合は長めに待機
61
+ else:
62
+ time.sleep(delay)
63
+ continue
64
+ else:
65
+ print(f"最大リトライ回数に達しました: {e}")
66
+ raise e
67
+ return None
68
+ return wrapper
69
+ return decorator
70
+
71
+ ## Cancer Name の抽出
72
  class ExtractTumorName(BaseModel):
73
  """Extract tumor name from the user's question."""
74
  tumor_name: str = Field(description="Extracted tumor name from the question, or 'None' if no tumor found")
 
76
  class TumorNameExtractor:
77
  def __init__(self, llm):
78
  self.llm = llm
 
 
79
  self.structured_llm_extractor = self.llm.with_structured_output(ExtractTumorName)
80
 
81
+ self.system_prompt = """あなたは、ユーザーの質問に基づいて腫瘍名を英語で抽出するシステムです。
82
+ 質問文に腫瘍の種類や名前が含まれている場合、それを英語で返してください。
83
+ 質問文に腫瘍名がない場合は 'None' と返答してください。"""
 
84
 
 
85
  self.grade_prompt = ChatPromptTemplate.from_messages(
86
  [
87
  ("system", self.system_prompt),
 
89
  ]
90
  )
91
 
92
+ @retry_on_error(max_retries=3, delay=2)
93
  def extract_tumor_name(self, question: str) -> str:
94
+ """腫瘍名を抽出するメソッド"""
95
+ try:
96
+ tumor_extractor = self.grade_prompt | self.structured_llm_extractor
97
+ result = tumor_extractor.invoke({"question": question})
98
+ return result.tumor_name
99
+ except Exception as e:
100
+ print(f"腫瘍名抽出エラー: {e}")
101
+ return "None"
 
 
 
102
 
103
+ ### 質問変更システム
104
  class ModifyQuestion(BaseModel):
105
  """Class for modifying a question by inserting NCTID."""
106
  modified_question: str = Field(description="The modified question with the inserted NCTID.")
 
108
  class QuestionModifier:
109
  def __init__(self, llm):
110
  self.llm = llm
 
 
111
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
112
 
113
+ # 修正: 中括弧をエスケープ
114
+ self.system_prompt = """あなたは、ユーザーの質問に対して適切なNCTIDを挿入して質問を変更するシステムです。
115
+ 質問文にNCTIDを挿入し、形式に基づいて新しい質問を生成してください。
116
+ 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては
117
+ 16歳男性の神経膠腫の患者さんは{{nct_id}}に参加できますか?と変更して下さい
118
+ NCTIDは {{nct_id}} を使用してください。"""
119
 
 
120
  self.modify_prompt = ChatPromptTemplate.from_messages(
121
  [
122
  ("system", self.system_prompt),
 
124
  ]
125
  )
126
 
127
+ @retry_on_error(max_retries=3, delay=2)
128
  def modify_question(self, question: str, nct_id: str) -> str:
129
+ """質問を変更するメソッド"""
130
+ try:
131
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
132
+ result = question_modifier.invoke({"question": question, "nct_id": nct_id})
133
+ return result.modified_question
134
+ except Exception as e:
135
+ print(f"質問変更エラー: {e}")
136
+ return f"{question} (NCTID: {nct_id})"
 
 
 
137
 
138
  class QuestionModifierSecond:
139
  def __init__(self, llm):
140
  self.llm = llm
 
 
141
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
142
 
143
+ self.system_prompt = """あなたは、ユーザーの質問を変更するシステムです。
144
+ 形式に基づいて新しい質問を生成してください。
145
+ 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては
146
+ 16歳男性の神経膠腫の患者さんはこの治験に参加できますか?と変更して下さい"""
 
 
147
 
 
148
  self.modify_prompt = ChatPromptTemplate.from_messages(
149
  [
150
  ("system", self.system_prompt),
 
152
  ]
153
  )
154
 
155
+ @retry_on_error(max_retries=3, delay=2)
156
  def modify_question(self, question: str) -> str:
157
+ """質問を変更するメソッド"""
158
+ try:
159
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
160
+ result = question_modifier.invoke({"question": question})
161
+ return result.modified_question
162
+ except Exception as e:
163
+ print(f"質問変更エラー: {e}")
164
+ return question
165
+
 
 
 
166
  class QuestionModifierEnglish:
167
  def __init__(self, llm):
168
  self.llm = llm
 
 
169
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
170
 
171
+ self.system_prompt = """あなたは、ユーザーの質問を変更し英語に翻訳するシステムです。
172
+ 形式に基づいて新しい質問を生成してください。
173
+ 例えば16歳男性の神経膠腫の患者さんが参加できる臨床治験を教えて下さいという質問に対しては
174
+ Can a 16 year old male patient with glioma participate in this clinical trial?と変更して下さい"""
 
 
175
 
 
176
  self.modify_prompt = ChatPromptTemplate.from_messages(
177
  [
178
  ("system", self.system_prompt),
 
180
  ]
181
  )
182
 
183
+ @retry_on_error(max_retries=3, delay=2)
184
  def modify_question(self, question: str) -> str:
185
+ """質問を変更するメソッド"""
186
+ try:
187
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
188
+ result = question_modifier.invoke({"question": question})
189
+ return result.modified_question
190
+ except Exception as e:
191
+ print(f"英語質問変更エラー: {e}")
192
+ return question
 
 
 
 
 
 
193
 
194
+ ### Make criteria check Agent
195
  class ClinicalTrialAgent:
196
  def __init__(self, llm, db):
197
  self.llm = llm
198
  self.db = db
199
 
 
200
  self.system_prompt = """
201
  あなたは患者さんに適した治験を探すエージェントです。
202
  データベースのEligibility Criteriaをチェックして患者さんがその治験を受けることが可能かどうか答えて下さい
203
  """
204
 
 
205
  self.prompt = ChatPromptTemplate.from_messages(
206
  [("system", self.system_prompt),
207
  ("human", "{input}"),
208
  MessagesPlaceholder("agent_scratchpad")]
209
  )
210
 
 
211
  self.agent_executor = self.create_sql_agent(self.llm, self.db, self.prompt)
212
 
213
  def create_sql_agent(self, llm, db, prompt):
 
221
  )
222
  return agent_executor
223
 
224
+ @retry_on_error(max_retries=3, delay=2)
225
  def get_agent_judgment(self, modify_question: str) -> str:
226
+ """Modifyされた質問を元に、患者さんが治験に参加可能かどうかのエージェント判断を取得"""
227
+ try:
228
+ result = self.agent_executor.invoke({"input": modify_question})
229
+ return result
230
+ except Exception as e:
231
+ print(f"エージェント判断エラー: {e}")
232
+ return f"エラー: {str(e)}"
 
 
233
 
234
  class SimpleClinicalTrialAgent:
235
  def __init__(self, llm):
236
  self.llm = llm
237
 
238
+ @retry_on_error(max_retries=3, delay=2)
239
  def evaluate_eligibility(self, TargetCriteria: str, question: str) -> str:
240
+ """臨床試験の参加適格性を評価するメソッド"""
241
+ try:
242
+ # 修正: プロンプト内の中括弧を適切にエスケープ
243
+ prompt_template = """
244
+ You are an agent looking for a suitable clinical trial for a patient.
245
+ Please answer whether the patient is eligible for this clinical trial based on the following criteria. If you do not know the answer, say you do not know. Your answer should be brief, no more than 3 sentences.
246
+
247
+ Question: {{question}}
248
+
249
+ Criteria:
250
+ {criteria}""".format(criteria=TargetCriteria)
251
+
252
+ criteria_prompt = ChatPromptTemplate.from_messages(
253
+ [
254
+ (
255
+ "human",
256
+ prompt_template
257
+ )
258
+ ]
259
+ )
260
+
261
+ rag_chain = (
262
+ {"question": RunnablePassthrough()}
263
+ | criteria_prompt
264
+ | self.llm
265
+ | StrOutputParser()
266
+ )
267
+
268
+ response = rag_chain.invoke(question)
269
+ return response
270
+
271
+ except Exception as e:
272
+ print(f"適格性評価エラー: {e}")
273
+ return f"評価エラー: {str(e)}"
 
 
 
274
 
275
  ### output 評価システム
276
  class TrialEligibilityGrader(BaseModel):
 
282
  class GraderAgent:
283
  def __init__(self, llm):
284
  self.llm = llm
 
 
285
  self.structured_llm_grader = self.llm.with_structured_output(TrialEligibilityGrader)
286
 
 
287
  self.system_prompt = """
288
  あなたは治験に参加する患者の適合性を評価するGraderです。
289
  以下のドキュメントを読み、患者が治験に参加可能かどうかを判断してください。
290
  'yes'(参加可能)、'no'(参加不可能)、'unclear'(判断できない)の3値で答えてください。
291
  """
292
 
 
293
  self.grade_prompt = ChatPromptTemplate.from_messages(
294
  [
295
  ("system", self.system_prompt),
 
300
  ]
301
  )
302
 
303
+ @retry_on_error(max_retries=3, delay=2)
304
  def evaluate_eligibility(self, AgentJudgment_output: str) -> str:
305
+ """AgentJudgment['output']を基に患者が治験に参加可能かどうかを評価し、スコア(AgentGrade)を返す"""
306
+ try:
307
+ GraderAgent = self.grade_prompt | self.structured_llm_grader
308
+ result = GraderAgent.invoke({"document": AgentJudgment_output})
309
+ return result.score
310
+ except Exception as e:
311
+ print(f"グレード評価エラー: {e}")
312
+ return "unclear"
 
 
 
313
 
314
  class LLMTranslator:
315
  def __init__(self, llm):
316
  self.llm = llm
317
  self.structured_llm_modifier = self.llm.with_structured_output(ModifyQuestion)
318
 
319
+ self.system_prompt = """あなたは、優秀な翻訳者です。
320
+ 日本語を英語に翻訳して下さい。"""
321
+
322
+ self.system_prompt2 = """あなたは、優秀な翻訳者です。
323
+ 日本語を英語に以下のフォーマットに従って翻訳して下さい。
324
+ MainQuestion:
325
+ Known gene mutation:
326
+ Measurable tumour:
327
+ Biopsiable tumour:"""
 
328
 
329
  self.modify_prompt = ChatPromptTemplate.from_messages(
330
  [
 
341
  )
342
 
343
  def is_english(self, text: str) -> bool:
344
+ """簡易的にテキストが英語かどうかを判定する関数"""
 
 
 
 
 
345
  return bool(re.match(r'^[A-Za-z0-9\s.,?!]+$', text))
346
 
347
+ @retry_on_error(max_retries=3, delay=2)
348
  def translate(self, question: str) -> str:
349
+ """質問を翻訳するメソッド。英語の質問はそのまま返す。"""
350
+ try:
351
+ if self.is_english(question):
352
+ return question
353
+
354
+ question_modifier = self.modify_prompt | self.structured_llm_modifier
355
+ result = question_modifier.invoke({"question": question})
356
+ return result.modified_question
357
+ except Exception as e:
358
+ print(f"翻訳エラー: {e}")
359
  return question
360
+
361
+ @retry_on_error(max_retries=3, delay=2)
 
 
 
 
 
362
  def translateQuestion(self, question: str) -> str:
363
+ """フォーマット付きで質問を翻訳するメソッド"""
364
+ try:
365
+ question_modifier = self.modify_prompt2 | self.structured_llm_modifier
366
+ result = question_modifier.invoke({"question": question})
367
+ return result.modified_question
368
+ except Exception as e:
369
+ print(f"フォーマット翻訳エラー: {e}")
370
+ return question
 
371
 
372
  def generate_ex_question(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
373
+ """日本語での質問文を生成"""
374
+ try:
375
+ # GeneMutationが空の場合はUnknownに設定
376
+ gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
377
+
378
+ # MeseableとBiopsiableの値をYes, No, Unknownに変換
379
+ meseable_text = (
380
+ "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
381
+ )
382
+ biopsiable_text = (
383
+ "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
384
+ )
385
+
386
+ # 質問文の生成
387
+ ex_question = f"""{age}歳{sex}の{tumor_type}患者さんはこの治験に参加することができますか?
388
  判明している遺伝子変異: {gene_mutation_text}
389
  Meseable tumor: {meseable_text}
390
  Biopsiable tumor: {biopsiable_text}
391
+ です。"""
392
+ return ex_question
393
+ except Exception as e:
394
+ print(f"日本語質問生成エラー: {e}")
395
+ return f"{age}歳{sex}の{tumor_type}患者さんの治験参加について"
396
 
397
  def generate_ex_question_English(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
398
+ """英語での質問文を生成"""
399
+ try:
400
+ # GeneMutationが空の場合は"Unknown"に設定
401
+ gene_mutation_text = GeneMutation if GeneMutation else "Unknown"
402
+
403
+ # sexの値を male または female に変換
404
+ sex_text = "male" if sex == "男性" else "female" if sex == "女性" else "Unknown"
405
+
406
+ # MeseableとBiopsiableの値を "Yes", "No", "Unknown" に変換
407
+ meseable_text = (
408
+ "Yes" if Meseable == "有り" else "No" if Meseable == "無し" else "Unknown"
409
+ )
410
+ biopsiable_text = (
411
+ "Yes" if Biopsiable == "有り" else "No" if Biopsiable == "無し" else "Unknown"
412
+ )
413
+
414
+ # 英語での質問文を生成
415
+ ex_question = f"""Can a {age}-year-old {sex_text} patient with {tumor_type} participate in this clinical trial?
416
  Known gene mutation: {gene_mutation_text}
417
  Measurable tumor: {meseable_text}
418
+ Biopsiable tumor: {biopsiable_text}"""
419
+ return ex_question
420
+ except Exception as e:
421
+ print(f"英語質問生成エラー: {e}")
422
+ return f"Can a {age}-year-old patient with {tumor_type} participate in this clinical trial?"
423
+
424
+ # テスト関数
425
+ def test_clinical_trial_tools():
426
+ """臨床試験ツールのテスト関数"""
427
+ try:
428
+ from langchain_groq import ChatGroq
429
+
430
+ # Groqクライアントの初期化
431
+ groq = ChatGroq(model_name="llama3-70b-8192", temperature=0)
432
+
433
+ # 各エージェントの初期化テスト
434
+ translator = LLMTranslator(groq)
435
+ criteria_agent = SimpleClinicalTrialAgent(groq)
436
+ grader_agent = GraderAgent(groq)
437
+
438
+ print("✅ 全てのエージェントが正常に初期化されました")
439
+
440
+ # サンプル質問の生成テスト
441
+ sample_question = generate_ex_question_English(
442
+ age="45",
443
+ sex="女性",
444
+ tumor_type="breast cancer",
445
+ GeneMutation="HER2",
446
+ Meseable="有り",
447
+ Biopsiable="有り"
448
+ )
449
+
450
+ print(f"✅ サンプル質問生成成功: {sample_question}")
451
+ return True
452
+
453
+ except Exception as e:
454
+ print(f"❌ テスト中にエラーが発生しました: {e}")
455
+ return False
456
+
457
+ if __name__ == "__main__":
458
+ print("ClinicalTrialTools のテストを開始します...")
459
+ success = test_clinical_trial_tools()
460
+ if success:
461
+ print("✅ テストが正常に完了しました。")
462
+ else:
463
+ print("❌ テストでエラーが発生しました。")
app copy.py DELETED
@@ -1,106 +0,0 @@
1
- import gradio as gr
2
- import pandas as pd
3
- from OpenAITools.FetchTools import fetch_clinical_trials
4
- from langchain_openai import ChatOpenAI
5
- from langchain_groq import ChatGroq
6
- from OpenAITools.CrinicalTrialTools import SimpleClinicalTrialAgent, GraderAgent, LLMTranslator, generate_ex_question_English
7
-
8
- # モデルとエージェントの初期化
9
- groq = ChatGroq(model_name="llama3-70b-8192", temperature=0)
10
- translator = LLMTranslator(groq)
11
- CriteriaCheckAgent = SimpleClinicalTrialAgent(groq)
12
- grader_agent = GraderAgent(groq)
13
-
14
- # データフレームを生成する関数
15
- def generate_dataframe(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
16
- # 日本語の腫瘍タイプを英語に翻訳
17
- TumorName = translator.translate(tumor_type)
18
-
19
- # 質問文を生成
20
- ex_question = generate_ex_question_English(age, sex, TumorName, GeneMutation, Meseable, Biopsiable)
21
-
22
- # 臨床試験データの取得
23
- df = fetch_clinical_trials(TumorName)
24
- df['AgentJudgment'] = None
25
- df['AgentGrade'] = None
26
-
27
- # 臨床試験の適格性の評価
28
- NCTIDs = list(df['NCTID'])
29
- progress = gr.Progress(track_tqdm=True)
30
- for i, nct_id in enumerate(NCTIDs):
31
- target_criteria = df.loc[df['NCTID'] == nct_id, 'Eligibility Criteria'].values[0]
32
- agent_judgment = CriteriaCheckAgent.evaluate_eligibility(target_criteria, ex_question)
33
- agent_grade = grader_agent.evaluate_eligibility(agent_judgment)
34
-
35
- # データフレームの更新
36
- df.loc[df['NCTID'] == nct_id, 'AgentJudgment'] = agent_judgment
37
- df.loc[df['NCTID'] == nct_id, 'AgentGrade'] = agent_grade
38
- progress((i + 1) / len(NCTIDs))
39
-
40
- # 列を指定した順に並び替え
41
- columns_order = ['NCTID', 'AgentGrade', 'Title', 'AgentJudgment', 'Japanes Locations',
42
- 'Primary Completion Date', 'Cancer', 'Summary', 'Eligibility Criteria']
43
- df = df[columns_order]
44
-
45
- return df, df # フィルタ用と表示用にデータフレームを返す
46
-
47
- # 特定のAgentGrade(yes, no, unclear)に基づいて行をフィルタリングする関数
48
- def filter_rows_by_grade(original_df, grade):
49
- df_filtered = original_df[original_df['AgentGrade'] == grade]
50
- return df_filtered, df_filtered
51
-
52
- # CSVとして保存しダウンロードする関数
53
- def download_filtered_csv(df):
54
- file_path = "filtered_data.csv"
55
- df.to_csv(file_path, index=False)
56
- return file_path
57
-
58
- # 全体結果をCSVとして保存しダウンロードする関数
59
- def download_full_csv(df):
60
- file_path = "full_data.csv"
61
- df.to_csv(file_path, index=False)
62
- return file_path
63
-
64
- # Gradioインターフェースの作成
65
- with gr.Blocks() as demo:
66
- gr.Markdown("## 臨床試験適格性評価インターフェース")
67
-
68
- # 各種入力フィールド
69
- age_input = gr.Textbox(label="Age", placeholder="例: 65")
70
- sex_input = gr.Dropdown(choices=["男性", "女性"], label="Sex")
71
- tumor_type_input = gr.Textbox(label="Tumor Type", placeholder="例: gastric cancer, 日本でも良いですが英語の方が精度が高いです。")
72
- gene_mutation_input = gr.Textbox(label="Gene Mutation", placeholder="例: HER2")
73
- measurable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Measurable Tumor")
74
- biopsiable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Biopsiable Tumor")
75
-
76
- # データフレーム表示エリア
77
- dataframe_output = gr.DataFrame()
78
- original_df = gr.State()
79
- filtered_df = gr.State()
80
-
81
- # データフレーム生成ボタン
82
- generate_button = gr.Button("Generate Clinical Trials Data")
83
-
84
- # フィルタリングボタン
85
- yes_button = gr.Button("Show Eligible Trials")
86
- no_button = gr.Button("Show Ineligible Trials")
87
- unclear_button = gr.Button("Show Unclear Trials")
88
-
89
- # ダウンロードボタン
90
- download_filtered_button = gr.Button("Download Filtered Data")
91
- download_filtered_output = gr.File(label="Download Filtered Data")
92
-
93
- download_full_button = gr.Button("Download Full Data")
94
- download_full_output = gr.File(label="Download Full Data")
95
-
96
-
97
- # ボタン動作の設定
98
- generate_button.click(fn=generate_dataframe, inputs=[age_input, sex_input, tumor_type_input, gene_mutation_input, measurable_input, biopsiable_input], outputs=[dataframe_output, original_df])
99
- yes_button.click(fn=filter_rows_by_grade, inputs=[original_df, gr.State("yes")], outputs=[dataframe_output, filtered_df])
100
- no_button.click(fn=filter_rows_by_grade, inputs=[original_df, gr.State("no")], outputs=[dataframe_output, filtered_df])
101
- unclear_button.click(fn=filter_rows_by_grade, inputs=[original_df, gr.State("unclear")], outputs=[dataframe_output, filtered_df])
102
- download_filtered_button.click(fn=download_filtered_csv, inputs=filtered_df, outputs=download_filtered_output)
103
- download_full_button.click(fn=download_full_csv, inputs=original_df, outputs=download_full_output)
104
-
105
- if __name__ == "__main__":
106
- demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py CHANGED
@@ -1,321 +1,106 @@
1
  import gradio as gr
2
  import pandas as pd
3
- import time
4
- import traceback
5
- import os
6
  from OpenAITools.FetchTools import fetch_clinical_trials
7
  from langchain_openai import ChatOpenAI
8
  from langchain_groq import ChatGroq
9
  from OpenAITools.CrinicalTrialTools import SimpleClinicalTrialAgent, GraderAgent, LLMTranslator, generate_ex_question_English
10
 
11
- # 環境変数チェック
12
- def check_environment():
13
- """環境変数をチェックし、不足している場合は警告"""
14
- missing_vars = []
15
-
16
- if not os.getenv("GROQ_API_KEY"):
17
- missing_vars.append("GROQ_API_KEY")
18
-
19
- if not os.getenv("OPENAI_API_KEY"):
20
- missing_vars.append("OPENAI_API_KEY")
21
-
22
- if missing_vars:
23
- print(f"⚠️ 環境変数が設定されていません: {', '.join(missing_vars)}")
24
- print("一部の機能が制限される可能性があります。")
25
-
26
- return len(missing_vars) == 0
27
-
28
- # 環境変数チェック実行
29
- env_ok = check_environment()
30
-
31
- # モデルとエージェントの安全な初期化
32
- def safe_init_agents():
33
- """エージェントを安全に初期化"""
34
- try:
35
- groq = ChatGroq(model_name="llama3-70b-8192", temperature=0)
36
- translator = LLMTranslator(groq)
37
- criteria_agent = SimpleClinicalTrialAgent(groq)
38
- grader_agent = GraderAgent(groq)
39
- return translator, criteria_agent, grader_agent
40
- except Exception as e:
41
- print(f"エージェント初期化エラー: {e}")
42
- return None, None, None
43
-
44
- # エージェント初期化
45
- translator, CriteriaCheckAgent, grader_agent = safe_init_agents()
46
-
47
- # エラーハンドリング付きでエージェント評価を実行する関数
48
- def evaluate_with_retry(agent, criteria, question, max_retries=3):
49
- """エラーハンドリング付きでエージェント評価を実行"""
50
- if agent is None:
51
- return "評価エラー: エージェントが初期化されていません。API keyを確認してください。"
52
-
53
- for attempt in range(max_retries):
54
- try:
55
- return agent.evaluate_eligibility(criteria, question)
56
- except Exception as e:
57
- if "missing variables" in str(e):
58
- # プロンプトテンプレートの変数エラーの場合
59
- print(f"プロンプトテンプレートエラー (試行 {attempt + 1}/{max_retries}): {e}")
60
- return "評価エラー: プロンプトテンプレートの設定に問題があります"
61
- elif "no healthy upstream" in str(e) or "InternalServerError" in str(e):
62
- # Groqサーバーエラーの場合
63
- print(f"Groqサーバーエラー (試行 {attempt + 1}/{max_retries}): {e}")
64
- if attempt < max_retries - 1:
65
- time.sleep(2) # 2秒待機してリトライ
66
- continue
67
- else:
68
- return "評価エラー: サーバーに接続できませんでした"
69
- elif "API key" in str(e) or "authentication" in str(e).lower():
70
- return "評価エラー: API keyが無効または設定されていません"
71
- else:
72
- print(f"予期しないエラー (試行 {attempt + 1}/{max_retries}): {e}")
73
- if attempt < max_retries - 1:
74
- time.sleep(1)
75
- continue
76
- else:
77
- return f"評価エラー: {str(e)}"
78
- return "評価エラー: 最大リトライ回数に達しました"
79
-
80
- def evaluate_grade_with_retry(agent, judgment, max_retries=3):
81
- """エラーハンドリング付きでグレード評価を実行"""
82
- if agent is None:
83
- return "unclear"
84
-
85
- for attempt in range(max_retries):
86
- try:
87
- return agent.evaluate_eligibility(judgment)
88
- except Exception as e:
89
- if "no healthy upstream" in str(e) or "InternalServerError" in str(e):
90
- print(f"Groqサーバーエラー (グレード評価 - 試行 {attempt + 1}/{max_retries}): {e}")
91
- if attempt < max_retries - 1:
92
- time.sleep(2)
93
- continue
94
- else:
95
- return "unclear"
96
- elif "API key" in str(e) or "authentication" in str(e).lower():
97
- return "unclear"
98
- else:
99
- print(f"予期しないエラー (グレード評価 - 試行 {attempt + 1}/{max_retries}): {e}")
100
- if attempt < max_retries - 1:
101
- time.sleep(1)
102
- continue
103
- else:
104
- return "unclear"
105
- return "unclear"
106
 
107
  # データフレームを生成する関数
108
  def generate_dataframe(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
109
- try:
110
- # 入力検証
111
- if not all([age, sex, tumor_type]):
112
- return pd.DataFrame(), pd.DataFrame()
113
-
114
- # 日本語の腫瘍タイプを英語に翻訳
115
- try:
116
- if translator is not None:
117
- TumorName = translator.translate(tumor_type)
118
- else:
119
- print("翻訳エージェントが利用できません。元の値を使用します。")
120
- TumorName = tumor_type
121
- except Exception as e:
122
- print(f"翻訳エラー: {e}")
123
- TumorName = tumor_type # 翻訳に失敗した場合は元の値を使用
124
-
125
- # 質問文を生成
126
- try:
127
- ex_question = generate_ex_question_English(age, sex, TumorName, GeneMutation, Meseable, Biopsiable)
128
- except Exception as e:
129
- print(f"質問生成エラー: {e}")
130
- return pd.DataFrame(), pd.DataFrame()
131
-
132
- # 臨床試験データの取得
133
- try:
134
- df = fetch_clinical_trials(TumorName)
135
- if df.empty:
136
- print("臨床試験データが見つかりませんでした")
137
- return pd.DataFrame(), pd.DataFrame()
138
- except Exception as e:
139
- print(f"臨床試験データ取得エラー: {e}")
140
- return pd.DataFrame(), pd.DataFrame()
141
-
142
- df['AgentJudgment'] = None
143
- df['AgentGrade'] = None
144
-
145
- # 臨床試験の適格性の評価
146
- NCTIDs = list(df['NCTID'])
147
- progress = gr.Progress(track_tqdm=True)
148
 
149
- for i, nct_id in enumerate(NCTIDs):
150
- try:
151
- target_criteria = df.loc[df['NCTID'] == nct_id, 'Eligibility Criteria'].values[0]
152
-
153
- # エラーハンドリング付きで評価実行
154
- agent_judgment = evaluate_with_retry(CriteriaCheckAgent, target_criteria, ex_question)
155
- agent_grade = evaluate_grade_with_retry(grader_agent, agent_judgment)
156
-
157
- # データフレームの更新
158
- df.loc[df['NCTID'] == nct_id, 'AgentJudgment'] = agent_judgment
159
- df.loc[df['NCTID'] == nct_id, 'AgentGrade'] = agent_grade
160
-
161
- except Exception as e:
162
- print(f"NCTID {nct_id} の評価中にエラー: {e}")
163
- df.loc[df['NCTID'] == nct_id, 'AgentJudgment'] = f"エラー: {str(e)}"
164
- df.loc[df['NCTID'] == nct_id, 'AgentGrade'] = "unclear"
165
-
166
- progress((i + 1) / len(NCTIDs))
167
 
168
- # 列を指定した順に並び替え
169
- columns_order = ['NCTID', 'AgentGrade', 'Title', 'AgentJudgment', 'Japanes Locations',
170
- 'Primary Completion Date', 'Cancer', 'Summary', 'Eligibility Criteria']
171
-
172
- # 存在する列のみを選択
173
- available_columns = [col for col in columns_order if col in df.columns]
174
- df = df[available_columns]
175
-
176
- return df, df # フィルタ用と表示用にデータフレームを返す
177
-
178
- except Exception as e:
179
- print(f"データフレーム生成中に予期しないエラー: {e}")
180
- traceback.print_exc()
181
- return pd.DataFrame(), pd.DataFrame()
182
 
183
  # CSVとして保存しダウンロードする関数
184
  def download_filtered_csv(df):
185
- try:
186
- if df is None or len(df) == 0:
187
- return None
188
- file_path = "filtered_data.csv"
189
- df.to_csv(file_path, index=False)
190
- return file_path
191
- except Exception as e:
192
- print(f"CSV保存エラー: {e}")
193
- return None
194
 
195
  # 全体結果をCSVとして保存しダウンロードする関数
196
  def download_full_csv(df):
197
- try:
198
- if df is None or len(df) == 0:
199
- return None
200
- file_path = "full_data.csv"
201
- df.to_csv(file_path, index=False)
202
- return file_path
203
- except Exception as e:
204
- print(f"CSV保存エラー: {e}")
205
- return None
206
 
207
  # Gradioインターフェースの作成
208
- with gr.Blocks(title="臨床試験適格性評価", theme=gr.themes.Soft()) as demo:
209
  gr.Markdown("## 臨床試験適格性評価インターフェース")
210
-
211
- # 環境変数状態の表示
212
- if env_ok:
213
- gr.Markdown("✅ **ステータス**: 全ての環境変数が設定されています")
214
- else:
215
- gr.Markdown("⚠️ **注意**: 一部の環境変数が設定されていません。機能が制限される可能性があります。")
216
-
217
- gr.Markdown("💡 **使用方法**: 患者情報を入力して「Generate Clinical Trials Data」をクリックしてください。")
218
 
219
  # 各種入力フィールド
220
- with gr.Row():
221
- with gr.Column():
222
- age_input = gr.Textbox(label="Age", placeholder="例: 65", value="")
223
- sex_input = gr.Dropdown(choices=["男性", "女性"], label="Sex", value=None)
224
- tumor_type_input = gr.Textbox(label="Tumor Type", placeholder="例: gastric cancer", value="")
225
-
226
- with gr.Column():
227
- gene_mutation_input = gr.Textbox(label="Gene Mutation", placeholder="例: HER2", value="")
228
- measurable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Measurable Tumor", value=None)
229
- biopsiable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Biopsiable Tumor", value=None)
230
 
231
  # データフレーム表示エリア
232
- dataframe_output = gr.DataFrame(
233
- headers=["NCTID", "AgentGrade", "Title", "AgentJudgment", "Status"],
234
- datatype=["str", "str", "str", "str", "str"],
235
- value=None
236
- )
237
-
238
- # 内部状態用の非表示コンポーネント
239
- original_df_state = gr.State(value=None)
240
- filtered_df_state = gr.State(value=None)
241
 
242
- # ボタン類
243
- with gr.Row():
244
- generate_button = gr.Button("Generate Clinical Trials Data", variant="primary")
245
-
246
- with gr.Row():
247
- yes_button = gr.Button("Show Eligible Trials", variant="secondary")
248
- no_button = gr.Button("Show Ineligible Trials", variant="secondary")
249
- unclear_button = gr.Button("Show Unclear Trials", variant="secondary")
250
-
251
- with gr.Row():
252
- download_filtered_button = gr.Button("Download Filtered Data")
253
- download_full_button = gr.Button("Download Full Data")
254
 
255
- # ダウンロードファイル
256
- download_filtered_output = gr.File(label="Download Filtered Data", visible=False)
257
- download_full_output = gr.File(label="Download Full Data", visible=False)
258
 
259
- # イベントハンドリング
260
- def update_dataframe_and_state(age, sex, tumor_type, gene_mutation, measurable, biopsiable):
261
- """データフレーム生成と状態更新"""
262
- df, _ = generate_dataframe(age, sex, tumor_type, gene_mutation, measurable, biopsiable)
263
- return df, df, df
264
 
265
- def filter_and_update(original_df, grade):
266
- """フィルタリングと表示更新"""
267
- if original_df is None or len(original_df) == 0:
268
- return original_df, original_df
269
-
270
- try:
271
- df_filtered = original_df[original_df['AgentGrade'] == grade]
272
- return df_filtered, df_filtered
273
- except Exception as e:
274
- print(f"フィルタリングエラー: {e}")
275
- return original_df, original_df
276
 
277
  # ボタン動作の設定
278
- generate_button.click(
279
- fn=update_dataframe_and_state,
280
- inputs=[age_input, sex_input, tumor_type_input, gene_mutation_input, measurable_input, biopsiable_input],
281
- outputs=[dataframe_output, original_df_state, filtered_df_state]
282
- )
283
-
284
- yes_button.click(
285
- fn=lambda df: filter_and_update(df, "yes"),
286
- inputs=[original_df_state],
287
- outputs=[dataframe_output, filtered_df_state]
288
- )
289
-
290
- no_button.click(
291
- fn=lambda df: filter_and_update(df, "no"),
292
- inputs=[original_df_state],
293
- outputs=[dataframe_output, filtered_df_state]
294
- )
295
-
296
- unclear_button.click(
297
- fn=lambda df: filter_and_update(df, "unclear"),
298
- inputs=[original_df_state],
299
- outputs=[dataframe_output, filtered_df_state]
300
- )
301
-
302
- download_filtered_button.click(
303
- fn=download_filtered_csv,
304
- inputs=[filtered_df_state],
305
- outputs=[download_filtered_output]
306
- )
307
-
308
- download_full_button.click(
309
- fn=download_full_csv,
310
- inputs=[original_df_state],
311
- outputs=[download_full_output]
312
- )
313
 
314
  if __name__ == "__main__":
315
- demo.launch(
316
- server_name="0.0.0.0",
317
- server_port=7860,
318
- share=False,
319
- debug=False,
320
- show_error=True
321
- )
 
1
  import gradio as gr
2
  import pandas as pd
 
 
 
3
  from OpenAITools.FetchTools import fetch_clinical_trials
4
  from langchain_openai import ChatOpenAI
5
  from langchain_groq import ChatGroq
6
  from OpenAITools.CrinicalTrialTools import SimpleClinicalTrialAgent, GraderAgent, LLMTranslator, generate_ex_question_English
7
 
8
+ # モデルとエージェントの初期化
9
+ groq = ChatGroq(model_name="llama3-70b-8192", temperature=0)
10
+ translator = LLMTranslator(groq)
11
+ CriteriaCheckAgent = SimpleClinicalTrialAgent(groq)
12
+ grader_agent = GraderAgent(groq)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  # データフレームを生成する関数
15
  def generate_dataframe(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
16
+ # 日本語の腫瘍タイプを英語に翻訳
17
+ TumorName = translator.translate(tumor_type)
18
+
19
+ # 質問文を生成
20
+ ex_question = generate_ex_question_English(age, sex, TumorName, GeneMutation, Meseable, Biopsiable)
21
+
22
+ # 臨床試験データの取得
23
+ df = fetch_clinical_trials(TumorName)
24
+ df['AgentJudgment'] = None
25
+ df['AgentGrade'] = None
26
+
27
+ # 臨床試験の適格性の評価
28
+ NCTIDs = list(df['NCTID'])
29
+ progress = gr.Progress(track_tqdm=True)
30
+ for i, nct_id in enumerate(NCTIDs):
31
+ target_criteria = df.loc[df['NCTID'] == nct_id, 'Eligibility Criteria'].values[0]
32
+ agent_judgment = CriteriaCheckAgent.evaluate_eligibility(target_criteria, ex_question)
33
+ agent_grade = grader_agent.evaluate_eligibility(agent_judgment)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
+ # データフレームの更新
36
+ df.loc[df['NCTID'] == nct_id, 'AgentJudgment'] = agent_judgment
37
+ df.loc[df['NCTID'] == nct_id, 'AgentGrade'] = agent_grade
38
+ progress((i + 1) / len(NCTIDs))
39
+
40
+ # 列を指定した順に並び替え
41
+ columns_order = ['NCTID', 'AgentGrade', 'Title', 'AgentJudgment', 'Japanes Locations',
42
+ 'Primary Completion Date', 'Cancer', 'Summary', 'Eligibility Criteria']
43
+ df = df[columns_order]
 
 
 
 
 
 
 
 
 
44
 
45
+ return df, df # フィルタ用と表示用にデータフレームを返す
46
+
47
+ # 特定のAgentGrade(yes, no, unclear)に基づいて行をフィルタリングする関数
48
+ def filter_rows_by_grade(original_df, grade):
49
+ df_filtered = original_df[original_df['AgentGrade'] == grade]
50
+ return df_filtered, df_filtered
 
 
 
 
 
 
 
 
51
 
52
  # CSVとして保存しダウンロードする関数
53
  def download_filtered_csv(df):
54
+ file_path = "filtered_data.csv"
55
+ df.to_csv(file_path, index=False)
56
+ return file_path
 
 
 
 
 
 
57
 
58
  # 全体結果をCSVとして保存しダウンロードする関数
59
  def download_full_csv(df):
60
+ file_path = "full_data.csv"
61
+ df.to_csv(file_path, index=False)
62
+ return file_path
 
 
 
 
 
 
63
 
64
  # Gradioインターフェースの作成
65
+ with gr.Blocks() as demo:
66
  gr.Markdown("## 臨床試験適格性評価インターフェース")
 
 
 
 
 
 
 
 
67
 
68
  # 各種入力フィールド
69
+ age_input = gr.Textbox(label="Age", placeholder="例: 65")
70
+ sex_input = gr.Dropdown(choices=["男性", "女性"], label="Sex")
71
+ tumor_type_input = gr.Textbox(label="Tumor Type", placeholder="例: gastric cancer, 日本でも良いですが英語の方が精度が高いです。")
72
+ gene_mutation_input = gr.Textbox(label="Gene Mutation", placeholder="例: HER2")
73
+ measurable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Measurable Tumor")
74
+ biopsiable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Biopsiable Tumor")
 
 
 
 
75
 
76
  # データフレーム表示エリア
77
+ dataframe_output = gr.DataFrame()
78
+ original_df = gr.State()
79
+ filtered_df = gr.State()
 
 
 
 
 
 
80
 
81
+ # データフレーム生成ボタン
82
+ generate_button = gr.Button("Generate Clinical Trials Data")
83
+
84
+ # フィルタリングボタン
85
+ yes_button = gr.Button("Show Eligible Trials")
86
+ no_button = gr.Button("Show Ineligible Trials")
87
+ unclear_button = gr.Button("Show Unclear Trials")
 
 
 
 
 
88
 
89
+ # ダウンロードボタン
90
+ download_filtered_button = gr.Button("Download Filtered Data")
91
+ download_filtered_output = gr.File(label="Download Filtered Data")
92
 
93
+ download_full_button = gr.Button("Download Full Data")
94
+ download_full_output = gr.File(label="Download Full Data")
 
 
 
95
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  # ボタン動作の設定
98
+ generate_button.click(fn=generate_dataframe, inputs=[age_input, sex_input, tumor_type_input, gene_mutation_input, measurable_input, biopsiable_input], outputs=[dataframe_output, original_df])
99
+ yes_button.click(fn=filter_rows_by_grade, inputs=[original_df, gr.State("yes")], outputs=[dataframe_output, filtered_df])
100
+ no_button.click(fn=filter_rows_by_grade, inputs=[original_df, gr.State("no")], outputs=[dataframe_output, filtered_df])
101
+ unclear_button.click(fn=filter_rows_by_grade, inputs=[original_df, gr.State("unclear")], outputs=[dataframe_output, filtered_df])
102
+ download_filtered_button.click(fn=download_filtered_csv, inputs=filtered_df, outputs=download_filtered_output)
103
+ download_full_button.click(fn=download_full_csv, inputs=original_df, outputs=download_full_output)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
104
 
105
  if __name__ == "__main__":
106
+ demo.launch()
 
 
 
 
 
 
app_new.py ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ import pandas as pd
3
+ import time
4
+ import traceback
5
+ import os
6
+ from OpenAITools.FetchTools import fetch_clinical_trials
7
+ from langchain_openai import ChatOpenAI
8
+ from langchain_groq import ChatGroq
9
+ from OpenAITools.CrinicalTrialTools import SimpleClinicalTrialAgent, GraderAgent, LLMTranslator, generate_ex_question_English
10
+
11
+ # 環境変数チェック
12
+ def check_environment():
13
+ """環境変数をチェックし、不足している場合は警告"""
14
+ missing_vars = []
15
+
16
+ if not os.getenv("GROQ_API_KEY"):
17
+ missing_vars.append("GROQ_API_KEY")
18
+
19
+ if not os.getenv("OPENAI_API_KEY"):
20
+ missing_vars.append("OPENAI_API_KEY")
21
+
22
+ if missing_vars:
23
+ print(f"⚠️ 環境変数が設定されていません: {', '.join(missing_vars)}")
24
+ print("一部の機能が制限される可能性があります。")
25
+
26
+ return len(missing_vars) == 0
27
+
28
+ # 環境変数チェック実行
29
+ env_ok = check_environment()
30
+
31
+ # モデルとエージェントの安全な初期化
32
+ def safe_init_agents():
33
+ """エージェントを安全に初期化"""
34
+ try:
35
+ groq = ChatGroq(model_name="llama3-70b-8192", temperature=0)
36
+ translator = LLMTranslator(groq)
37
+ criteria_agent = SimpleClinicalTrialAgent(groq)
38
+ grader_agent = GraderAgent(groq)
39
+ return translator, criteria_agent, grader_agent
40
+ except Exception as e:
41
+ print(f"エージェント初期化エラー: {e}")
42
+ return None, None, None
43
+
44
+ # エージェント初期化
45
+ translator, CriteriaCheckAgent, grader_agent = safe_init_agents()
46
+
47
+ # エラーハンドリング付きでエージェント評価を実行する関数
48
+ def evaluate_with_retry(agent, criteria, question, max_retries=3):
49
+ """エラーハンドリング付きでエージェント評価を実行"""
50
+ if agent is None:
51
+ return "評価エラー: エージェントが初期化されていません。API keyを確認してください。"
52
+
53
+ for attempt in range(max_retries):
54
+ try:
55
+ return agent.evaluate_eligibility(criteria, question)
56
+ except Exception as e:
57
+ if "missing variables" in str(e):
58
+ # プロンプトテンプレートの変数エラーの場合
59
+ print(f"プロンプトテンプレートエラー (試行 {attempt + 1}/{max_retries}): {e}")
60
+ return "評価エラー: プロンプトテンプレートの設定に問題があります"
61
+ elif "no healthy upstream" in str(e) or "InternalServerError" in str(e):
62
+ # Groqサーバーエラーの場合
63
+ print(f"Groqサーバーエラー (試行 {attempt + 1}/{max_retries}): {e}")
64
+ if attempt < max_retries - 1:
65
+ time.sleep(2) # 2秒待機してリトライ
66
+ continue
67
+ else:
68
+ return "評価エラー: サーバーに接続できませんでした"
69
+ elif "API key" in str(e) or "authentication" in str(e).lower():
70
+ return "評価エラー: API keyが無効または設定されていません"
71
+ else:
72
+ print(f"予期しないエラー (試行 {attempt + 1}/{max_retries}): {e}")
73
+ if attempt < max_retries - 1:
74
+ time.sleep(1)
75
+ continue
76
+ else:
77
+ return f"評価エラー: {str(e)}"
78
+ return "評価エラー: 最大リトライ回数に達しました"
79
+
80
+ def evaluate_grade_with_retry(agent, judgment, max_retries=3):
81
+ """エラーハンドリング付きでグレード評価を実行"""
82
+ if agent is None:
83
+ return "unclear"
84
+
85
+ for attempt in range(max_retries):
86
+ try:
87
+ return agent.evaluate_eligibility(judgment)
88
+ except Exception as e:
89
+ if "no healthy upstream" in str(e) or "InternalServerError" in str(e):
90
+ print(f"Groqサーバーエラー (グレード評価 - 試行 {attempt + 1}/{max_retries}): {e}")
91
+ if attempt < max_retries - 1:
92
+ time.sleep(2)
93
+ continue
94
+ else:
95
+ return "unclear"
96
+ elif "API key" in str(e) or "authentication" in str(e).lower():
97
+ return "unclear"
98
+ else:
99
+ print(f"予期しないエラー (グレード評価 - 試行 {attempt + 1}/{max_retries}): {e}")
100
+ if attempt < max_retries - 1:
101
+ time.sleep(1)
102
+ continue
103
+ else:
104
+ return "unclear"
105
+ return "unclear"
106
+
107
+ # データフレームを生成する関数
108
+ def generate_dataframe(age, sex, tumor_type, GeneMutation, Meseable, Biopsiable):
109
+ try:
110
+ # 入力検証
111
+ if not all([age, sex, tumor_type]):
112
+ return pd.DataFrame(), pd.DataFrame()
113
+
114
+ # 日本語の腫瘍タイプを英語に翻訳
115
+ try:
116
+ if translator is not None:
117
+ TumorName = translator.translate(tumor_type)
118
+ else:
119
+ print("翻訳エージェントが利用できません。元の値を使用します。")
120
+ TumorName = tumor_type
121
+ except Exception as e:
122
+ print(f"翻訳エラー: {e}")
123
+ TumorName = tumor_type # 翻訳に失敗した場合は元の値を使用
124
+
125
+ # 質問文を生成
126
+ try:
127
+ ex_question = generate_ex_question_English(age, sex, TumorName, GeneMutation, Meseable, Biopsiable)
128
+ except Exception as e:
129
+ print(f"質問生成エラー: {e}")
130
+ return pd.DataFrame(), pd.DataFrame()
131
+
132
+ # 臨床試験データの取得
133
+ try:
134
+ df = fetch_clinical_trials(TumorName)
135
+ if df.empty:
136
+ print("臨床試験データが見つかりませんでした")
137
+ return pd.DataFrame(), pd.DataFrame()
138
+ except Exception as e:
139
+ print(f"臨床試験データ取得エラー: {e}")
140
+ return pd.DataFrame(), pd.DataFrame()
141
+
142
+ df['AgentJudgment'] = None
143
+ df['AgentGrade'] = None
144
+
145
+ # 臨床試験の適格性の評価
146
+ NCTIDs = list(df['NCTID'])
147
+ progress = gr.Progress(track_tqdm=True)
148
+
149
+ for i, nct_id in enumerate(NCTIDs):
150
+ try:
151
+ target_criteria = df.loc[df['NCTID'] == nct_id, 'Eligibility Criteria'].values[0]
152
+
153
+ # エラーハンドリング付きで評価実行
154
+ agent_judgment = evaluate_with_retry(CriteriaCheckAgent, target_criteria, ex_question)
155
+ agent_grade = evaluate_grade_with_retry(grader_agent, agent_judgment)
156
+
157
+ # データフレームの更新
158
+ df.loc[df['NCTID'] == nct_id, 'AgentJudgment'] = agent_judgment
159
+ df.loc[df['NCTID'] == nct_id, 'AgentGrade'] = agent_grade
160
+
161
+ except Exception as e:
162
+ print(f"NCTID {nct_id} の評価中にエラー: {e}")
163
+ df.loc[df['NCTID'] == nct_id, 'AgentJudgment'] = f"エラー: {str(e)}"
164
+ df.loc[df['NCTID'] == nct_id, 'AgentGrade'] = "unclear"
165
+
166
+ progress((i + 1) / len(NCTIDs))
167
+
168
+ # 列を指定した順に並び替え
169
+ columns_order = ['NCTID', 'AgentGrade', 'Title', 'AgentJudgment', 'Japanes Locations',
170
+ 'Primary Completion Date', 'Cancer', 'Summary', 'Eligibility Criteria']
171
+
172
+ # 存在する列のみを選択
173
+ available_columns = [col for col in columns_order if col in df.columns]
174
+ df = df[available_columns]
175
+
176
+ return df, df # フィルタ用と表示用にデータフレームを返す
177
+
178
+ except Exception as e:
179
+ print(f"データフレーム生成中に予期しないエラー: {e}")
180
+ traceback.print_exc()
181
+ return pd.DataFrame(), pd.DataFrame()
182
+
183
+ # CSVとして保存しダウンロードする関数
184
+ def download_filtered_csv(df):
185
+ try:
186
+ if df is None or len(df) == 0:
187
+ return None
188
+ file_path = "filtered_data.csv"
189
+ df.to_csv(file_path, index=False)
190
+ return file_path
191
+ except Exception as e:
192
+ print(f"CSV保存エラー: {e}")
193
+ return None
194
+
195
+ # 全体結果をCSVとして保存しダウンロードする関数
196
+ def download_full_csv(df):
197
+ try:
198
+ if df is None or len(df) == 0:
199
+ return None
200
+ file_path = "full_data.csv"
201
+ df.to_csv(file_path, index=False)
202
+ return file_path
203
+ except Exception as e:
204
+ print(f"CSV保存エラー: {e}")
205
+ return None
206
+
207
+ # Gradioインターフェースの作成
208
+ with gr.Blocks(title="臨床試験適格性評価", theme=gr.themes.Soft()) as demo:
209
+ gr.Markdown("## 臨床試験適格性評価インターフェース")
210
+
211
+ # 環境変数状態の表示
212
+ if env_ok:
213
+ gr.Markdown("✅ **ステータス**: 全ての環境変数が設定されています")
214
+ else:
215
+ gr.Markdown("⚠️ **注意**: 一部の環境変数が設定されていません。機能が制限される可能性があります。")
216
+
217
+ gr.Markdown("💡 **使用方法**: 患者情報を入力して「Generate Clinical Trials Data」をクリックしてください。")
218
+
219
+ # 各種入力フィールド
220
+ with gr.Row():
221
+ with gr.Column():
222
+ age_input = gr.Textbox(label="Age", placeholder="例: 65", value="")
223
+ sex_input = gr.Dropdown(choices=["男性", "女性"], label="Sex", value=None)
224
+ tumor_type_input = gr.Textbox(label="Tumor Type", placeholder="例: gastric cancer", value="")
225
+
226
+ with gr.Column():
227
+ gene_mutation_input = gr.Textbox(label="Gene Mutation", placeholder="例: HER2", value="")
228
+ measurable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Measurable Tumor", value=None)
229
+ biopsiable_input = gr.Dropdown(choices=["有り", "無し", "不明"], label="Biopsiable Tumor", value=None)
230
+
231
+ # データフレーム表示エリア
232
+ dataframe_output = gr.DataFrame(
233
+ headers=["NCTID", "AgentGrade", "Title", "AgentJudgment", "Status"],
234
+ datatype=["str", "str", "str", "str", "str"],
235
+ value=None
236
+ )
237
+
238
+ # 内部状態用の非表示コンポーネント
239
+ original_df_state = gr.State(value=None)
240
+ filtered_df_state = gr.State(value=None)
241
+
242
+ # ボタン類
243
+ with gr.Row():
244
+ generate_button = gr.Button("Generate Clinical Trials Data", variant="primary")
245
+
246
+ with gr.Row():
247
+ yes_button = gr.Button("Show Eligible Trials", variant="secondary")
248
+ no_button = gr.Button("Show Ineligible Trials", variant="secondary")
249
+ unclear_button = gr.Button("Show Unclear Trials", variant="secondary")
250
+
251
+ with gr.Row():
252
+ download_filtered_button = gr.Button("Download Filtered Data")
253
+ download_full_button = gr.Button("Download Full Data")
254
+
255
+ # ダウンロードファイル
256
+ download_filtered_output = gr.File(label="Download Filtered Data", visible=False)
257
+ download_full_output = gr.File(label="Download Full Data", visible=False)
258
+
259
+ # イベントハンドリング
260
+ def update_dataframe_and_state(age, sex, tumor_type, gene_mutation, measurable, biopsiable):
261
+ """データフレーム生成と状態更新"""
262
+ df, _ = generate_dataframe(age, sex, tumor_type, gene_mutation, measurable, biopsiable)
263
+ return df, df, df
264
+
265
+ def filter_and_update(original_df, grade):
266
+ """フィルタリングと表示更新"""
267
+ if original_df is None or len(original_df) == 0:
268
+ return original_df, original_df
269
+
270
+ try:
271
+ df_filtered = original_df[original_df['AgentGrade'] == grade]
272
+ return df_filtered, df_filtered
273
+ except Exception as e:
274
+ print(f"フィルタリングエラー: {e}")
275
+ return original_df, original_df
276
+
277
+ # ボタン動作の設定
278
+ generate_button.click(
279
+ fn=update_dataframe_and_state,
280
+ inputs=[age_input, sex_input, tumor_type_input, gene_mutation_input, measurable_input, biopsiable_input],
281
+ outputs=[dataframe_output, original_df_state, filtered_df_state]
282
+ )
283
+
284
+ yes_button.click(
285
+ fn=lambda df: filter_and_update(df, "yes"),
286
+ inputs=[original_df_state],
287
+ outputs=[dataframe_output, filtered_df_state]
288
+ )
289
+
290
+ no_button.click(
291
+ fn=lambda df: filter_and_update(df, "no"),
292
+ inputs=[original_df_state],
293
+ outputs=[dataframe_output, filtered_df_state]
294
+ )
295
+
296
+ unclear_button.click(
297
+ fn=lambda df: filter_and_update(df, "unclear"),
298
+ inputs=[original_df_state],
299
+ outputs=[dataframe_output, filtered_df_state]
300
+ )
301
+
302
+ download_filtered_button.click(
303
+ fn=download_filtered_csv,
304
+ inputs=[filtered_df_state],
305
+ outputs=[download_filtered_output]
306
+ )
307
+
308
+ download_full_button.click(
309
+ fn=download_full_csv,
310
+ inputs=[original_df_state],
311
+ outputs=[download_full_output]
312
+ )
313
+
314
+ if __name__ == "__main__":
315
+ demo.launch(
316
+ server_name="0.0.0.0",
317
+ server_port=7860,
318
+ share=False,
319
+ debug=False,
320
+ show_error=True
321
+ )
requirements.txt → requirements_new.txt RENAMED
File without changes