moazx commited on
Commit
ddc9c77
·
1 Parent(s): 7a527fe

Enhance API security and functionality by adding authentication middleware and session management. Updated app.py to include the new auth router and integrated authentication checks for protected endpoints. Modified requirements.txt to include necessary libraries for session handling. Updated .env.example to include authentication credentials. Improved retrieval functions with query expansion for better medical term matching and enriched context in responses.

Browse files
.env.example CHANGED
@@ -6,4 +6,8 @@ LANGSMITH_API_KEY=
6
  LANGSMITH_PROJECT=
7
  LANGCHAIN_PROJECT=
8
 
9
- LANGSMITH_URL=
 
 
 
 
 
6
  LANGSMITH_PROJECT=
7
  LANGCHAIN_PROJECT=
8
 
9
+ LANGSMITH_URL=
10
+
11
+ # Authentication credentials
12
+ AUTH_USERNAME=volaris
13
+ AUTH_PASSWORD=volaris
.gitignore CHANGED
@@ -207,4 +207,4 @@ marimo/_lsp/
207
  __marimo__/
208
 
209
  # Frontend
210
- frontend/
 
207
  __marimo__/
208
 
209
  # Frontend
210
+ # frontend/
0.0.18 ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Defaulting to user installation because normal site-packages is not writeable
2
+ Requirement already satisfied: python-multipart in c:\users\moaze\appdata\roaming\python\python313\site-packages (0.0.9)
api/__pycache__/app.cpython-313.pyc CHANGED
Binary files a/api/__pycache__/app.cpython-313.pyc and b/api/__pycache__/app.cpython-313.pyc differ
 
api/__pycache__/middleware.cpython-313.pyc CHANGED
Binary files a/api/__pycache__/middleware.cpython-313.pyc and b/api/__pycache__/middleware.cpython-313.pyc differ
 
api/app.py CHANGED
@@ -6,11 +6,12 @@ from fastapi.exceptions import RequestValidationError
6
  from starlette.exceptions import HTTPException as StarletteHTTPException
7
 
8
  # Import routers
9
- from api.routers import medical, health, export
10
  from api.middleware import (
11
  ProcessTimeMiddleware,
12
  LoggingMiddleware,
13
  RateLimitMiddleware,
 
14
  get_cors_middleware_config
15
  )
16
  from fastapi.middleware.cors import CORSMiddleware
@@ -63,6 +64,7 @@ app.add_middleware(CORSMiddleware, **get_cors_middleware_config())
63
  app.add_middleware(ProcessTimeMiddleware)
64
  app.add_middleware(LoggingMiddleware)
65
  app.add_middleware(RateLimitMiddleware, calls_per_minute=100) # Adjust as needed
 
66
 
67
  # Add exception handlers
68
  app.add_exception_handler(HTTPException, http_exception_handler)
@@ -71,6 +73,7 @@ app.add_exception_handler(StarletteHTTPException, starlette_exception_handler)
71
  app.add_exception_handler(Exception, general_exception_handler)
72
 
73
  # Include routers
 
74
  app.include_router(health.router)
75
  app.include_router(medical.router)
76
  app.include_router(export.router)
 
6
  from starlette.exceptions import HTTPException as StarletteHTTPException
7
 
8
  # Import routers
9
+ from api.routers import medical, health, export, auth
10
  from api.middleware import (
11
  ProcessTimeMiddleware,
12
  LoggingMiddleware,
13
  RateLimitMiddleware,
14
+ AuthenticationMiddleware,
15
  get_cors_middleware_config
16
  )
17
  from fastapi.middleware.cors import CORSMiddleware
 
64
  app.add_middleware(ProcessTimeMiddleware)
65
  app.add_middleware(LoggingMiddleware)
66
  app.add_middleware(RateLimitMiddleware, calls_per_minute=100) # Adjust as needed
67
+ app.add_middleware(AuthenticationMiddleware) # Protect API endpoints
68
 
69
  # Add exception handlers
70
  app.add_exception_handler(HTTPException, http_exception_handler)
 
73
  app.add_exception_handler(Exception, general_exception_handler)
74
 
75
  # Include routers
76
+ app.include_router(auth.router)
77
  app.include_router(health.router)
78
  app.include_router(medical.router)
79
  app.include_router(export.router)
api/middleware.py CHANGED
@@ -3,8 +3,8 @@ Middleware for Medical RAG AI Advisor API
3
  """
4
  import time
5
  import logging
6
- from typing import Callable, Awaitable
7
- from fastapi import Request, Response, HTTPException
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from starlette.middleware.base import BaseHTTPMiddleware
10
 
@@ -90,6 +90,53 @@ class RateLimitMiddleware(BaseHTTPMiddleware):
90
  return await call_next(request)
91
 
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  def get_cors_middleware_config():
94
  """Get CORS middleware configuration"""
95
  return {
 
3
  """
4
  import time
5
  import logging
6
+ from typing import Callable, Awaitable, Optional
7
+ from fastapi import Request, Response, HTTPException, Cookie
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from starlette.middleware.base import BaseHTTPMiddleware
10
 
 
90
  return await call_next(request)
91
 
92
 
93
+ class AuthenticationMiddleware(BaseHTTPMiddleware):
94
+ """Middleware to protect endpoints with session authentication"""
95
+
96
+ # Paths that don't require authentication
97
+ PUBLIC_PATHS = [
98
+ "/",
99
+ "/docs",
100
+ "/redoc",
101
+ "/openapi.json",
102
+ "/health",
103
+ "/auth/login",
104
+ "/auth/status",
105
+ ]
106
+
107
+ async def dispatch(self, request: Request, call_next: Callable) -> Response:
108
+ # Check if path is public
109
+ path = request.url.path
110
+
111
+ # Allow public paths
112
+ if any(path.startswith(public_path) for public_path in self.PUBLIC_PATHS):
113
+ return await call_next(request)
114
+
115
+ # Check for session token
116
+ session_token = request.cookies.get("session_token")
117
+
118
+ if not session_token:
119
+ raise HTTPException(
120
+ status_code=401,
121
+ detail="Authentication required"
122
+ )
123
+
124
+ # Verify session
125
+ from api.routers.auth import verify_session
126
+ session_data = verify_session(session_token)
127
+
128
+ if not session_data:
129
+ raise HTTPException(
130
+ status_code=401,
131
+ detail="Invalid or expired session"
132
+ )
133
+
134
+ # Add user info to request state
135
+ request.state.user = session_data.get("username")
136
+
137
+ return await call_next(request)
138
+
139
+
140
  def get_cors_middleware_config():
141
  """Get CORS middleware configuration"""
142
  return {
api/routers/__pycache__/medical.cpython-313.pyc CHANGED
Binary files a/api/routers/__pycache__/medical.cpython-313.pyc and b/api/routers/__pycache__/medical.cpython-313.pyc differ
 
api/routers/auth.py ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Authentication router for simple login system
3
+ """
4
+ import os
5
+ import secrets
6
+ from datetime import datetime, timedelta
7
+ from typing import Dict, Optional
8
+ from fastapi import APIRouter, HTTPException, Response, Cookie, Form
9
+ from fastapi.responses import JSONResponse
10
+ from pydantic import BaseModel
11
+ from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired
12
+ import logging
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ router = APIRouter(prefix="/auth", tags=["Authentication"])
17
+
18
+ # Session management
19
+ SESSION_SECRET_KEY = os.getenv("SESSION_SECRET_KEY", secrets.token_hex(32))
20
+ SESSION_MAX_AGE = 86400 # 24 hours in seconds
21
+ serializer = URLSafeTimedSerializer(SESSION_SECRET_KEY)
22
+
23
+ # In-memory session store (for simple use case)
24
+ # For production, consider using Redis or database
25
+ active_sessions: Dict[str, dict] = {}
26
+
27
+
28
+ class LoginRequest(BaseModel):
29
+ username: str
30
+ password: str
31
+
32
+
33
+ class LoginResponse(BaseModel):
34
+ success: bool
35
+ message: str
36
+
37
+
38
+ def create_session(username: str) -> str:
39
+ """Create a new session token"""
40
+ session_id = secrets.token_urlsafe(32)
41
+ session_data = {
42
+ "username": username,
43
+ "created_at": datetime.utcnow().isoformat(),
44
+ "expires_at": (datetime.utcnow() + timedelta(seconds=SESSION_MAX_AGE)).isoformat()
45
+ }
46
+
47
+ # Store session
48
+ active_sessions[session_id] = session_data
49
+
50
+ # Create signed token
51
+ token = serializer.dumps(session_id)
52
+ return token
53
+
54
+
55
+ def verify_session(token: Optional[str]) -> Optional[dict]:
56
+ """Verify session token and return session data"""
57
+ if not token:
58
+ return None
59
+
60
+ try:
61
+ # Verify signature and age
62
+ session_id = serializer.loads(token, max_age=SESSION_MAX_AGE)
63
+
64
+ # Check if session exists
65
+ session_data = active_sessions.get(session_id)
66
+ if not session_data:
67
+ return None
68
+
69
+ # Check expiration
70
+ expires_at = datetime.fromisoformat(session_data["expires_at"])
71
+ if datetime.utcnow() > expires_at:
72
+ # Clean up expired session
73
+ active_sessions.pop(session_id, None)
74
+ return None
75
+
76
+ return session_data
77
+ except (BadSignature, SignatureExpired):
78
+ return None
79
+ except Exception as e:
80
+ logger.error(f"Session verification error: {e}")
81
+ return None
82
+
83
+
84
+ def verify_credentials(username: str, password: str) -> bool:
85
+ """Verify username and password against environment variables"""
86
+ expected_username = os.getenv("AUTH_USERNAME", "volaris")
87
+ expected_password = os.getenv("AUTH_PASSWORD", "volaris")
88
+
89
+ return username == expected_username and password == expected_password
90
+
91
+
92
+ @router.post("/login", response_model=LoginResponse)
93
+ async def login(
94
+ response: Response,
95
+ username: str = Form(...),
96
+ password: str = Form(...)
97
+ ):
98
+ """
99
+ Login endpoint - validates credentials and creates session
100
+ """
101
+ # Verify credentials
102
+ if not verify_credentials(username, password):
103
+ logger.warning(f"Failed login attempt for username: {username}")
104
+ raise HTTPException(status_code=401, detail="Invalid username or password")
105
+
106
+ # Create session
107
+ token = create_session(username)
108
+
109
+ # Set secure cookie
110
+ response.set_cookie(
111
+ key="session_token",
112
+ value=token,
113
+ httponly=True,
114
+ max_age=SESSION_MAX_AGE,
115
+ samesite="lax",
116
+ secure=False # Set to True in production with HTTPS
117
+ )
118
+
119
+ logger.info(f"Successful login for user: {username}")
120
+
121
+ return LoginResponse(
122
+ success=True,
123
+ message="Login successful"
124
+ )
125
+
126
+
127
+ @router.post("/logout")
128
+ async def logout(
129
+ response: Response,
130
+ session_token: Optional[str] = Cookie(None)
131
+ ):
132
+ """
133
+ Logout endpoint - invalidates session
134
+ """
135
+ if session_token:
136
+ try:
137
+ session_id = serializer.loads(session_token, max_age=SESSION_MAX_AGE)
138
+ active_sessions.pop(session_id, None)
139
+ except Exception:
140
+ pass
141
+
142
+ # Clear cookie
143
+ response.delete_cookie(key="session_token")
144
+
145
+ return {"success": True, "message": "Logged out successfully"}
146
+
147
+
148
+ @router.get("/verify")
149
+ async def verify(session_token: Optional[str] = Cookie(None)):
150
+ """
151
+ Verify if current session is valid
152
+ """
153
+ session_data = verify_session(session_token)
154
+
155
+ if not session_data:
156
+ raise HTTPException(status_code=401, detail="Not authenticated")
157
+
158
+ return {
159
+ "authenticated": True,
160
+ "username": session_data.get("username")
161
+ }
162
+
163
+
164
+ @router.get("/status")
165
+ async def status(session_token: Optional[str] = Cookie(None)):
166
+ """
167
+ Check authentication status without raising exception
168
+ """
169
+ session_data = verify_session(session_token)
170
+
171
+ return {
172
+ "authenticated": session_data is not None,
173
+ "username": session_data.get("username") if session_data else None
174
+ }
core/__pycache__/agent.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/agent.cpython-313.pyc and b/core/__pycache__/agent.cpython-313.pyc differ
 
core/__pycache__/background_init.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/background_init.cpython-313.pyc and b/core/__pycache__/background_init.cpython-313.pyc differ
 
core/__pycache__/github_storage.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/github_storage.cpython-313.pyc and b/core/__pycache__/github_storage.cpython-313.pyc differ
 
core/__pycache__/retrievers.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/retrievers.cpython-313.pyc and b/core/__pycache__/retrievers.cpython-313.pyc differ
 
core/__pycache__/tools.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/tools.cpython-313.pyc and b/core/__pycache__/tools.cpython-313.pyc differ
 
core/__pycache__/validation.cpython-313.pyc CHANGED
Binary files a/core/__pycache__/validation.cpython-313.pyc and b/core/__pycache__/validation.cpython-313.pyc differ
 
core/agent.py CHANGED
@@ -89,52 +89,89 @@ AVAILABLE_TOOLS = [
89
 
90
  # System message template for the agent
91
  SYSTEM_MESSAGE = """
92
- You are an advanced Medical Advisor Chatbot for healthcare professionals.
93
- Your primary purpose is to answer clinical and medical questions strictly based on authoritative medical guidelines using the tool "medical_guidelines_knowledge_tool".
94
-
95
- Your answers must be concise, medically informative, evidence-based responses in an authoritative, precise, and clinical tone.
96
- You will be responding to practicing medical professionals so adjust your answer and language accordingly.
97
-
98
- **INSTRUCTIONS:**
99
- - Always answer using only the information retrieved from medical guidelines via "medical_guidelines_knowledge_tool".
100
- - **SIDE EFFECT REPORTING**: When a healthcare professional reports an adverse drug reaction, side effect, or medication-related complication, ALWAYS use the "side_effect_recording_tool" first to document the information. Return the tool's response directly to the user without modification. DO NOT use validation or generate additional reports for side effect reporting queries.
101
- - Use the side effect recording tool when the input contains phrases like: "patient experienced", "side effect", "adverse reaction", "drug reaction", "medication caused", "developed after taking", etc.
102
- - When the side effect recording tool requests additional information, present the request exactly as provided by the tool.
103
- - **PROVIDER COMPARISON**: When the user asks to compare guidance between two providers (e.g., "compare NCCN vs ESMO on ..."), use the "compare_providers_tool" with appropriate `provider_a` and `provider_b` values to retrieve side-by-side, cited results.
104
- - **TIME/DATE QUERIES**: For any questions about the current date/time or references like "today" or "now", use the "get_current_datetime_tool". Treat this tool as the only reliable source of current time information.
105
- - For every answer, you MUST provide detailed citations including:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  * Source file name
107
- * Page number
108
- * Provider name
109
- * Specific location (e.g., Table 1, Figure 2, Box 3, Section Header, etc.)
110
- * Type of content (e.g., table, flowchart, bullet point, paragraph, etc.)
111
- - Use this format for citations:
112
- (Source: [file name], Page: [page number], Provider: [provider name], Location: [specific location], Type: [content type])
 
113
  - If multiple sources are used, cite each one with its corresponding metadata.
114
  - If a specific provider (NCCN, ASCO, ESMO, etc.) is mentioned in the question, prioritize information from that provider.
115
  - When citing tables or flowcharts:
116
- * Specify the table/figure number if available
117
- * Describe which part of the table/figure contains the information
118
- * Reference any relevant footnotes or legends
 
119
  - When citing text:
120
- * Specify the section or subsection heading
121
- * Indicate if it's from a bullet point, paragraph, or other format
122
-
123
- - If the answer is not found in the retrieved guidelines, provide a helpful response that:
124
- * Acknowledges the limitation: "Based on the available medical guidelines in my knowledge base, I could not find specific information about [topic]."
 
 
 
125
  * Suggests alternatives: "You may want to:
126
  - Rephrase your question with more specific clinical details
127
  - Specify a particular guideline provider (NCCN, ASCO, ESMO, NICE)
128
  - Consult the latest published guidelines directly for emerging topics"
129
  * Maintains professionalism: Never simply say "I don't know" - always provide context and next steps
130
- - Never speculate or provide information not present in the guidelines.
 
 
131
  - Always respond in English.
132
 
133
- **FORMATTING:**
134
- - Use markdown formatting for clarity:
135
- * Use bullet points for lists
136
- * Use bold for emphasis on key points
137
- * Use tables when summarizing multiple points
 
 
 
 
138
 
139
  **SAFETY DISCLAIMER:**
140
  Important: For emergencies call emergency services immediately. This is educational information for healthcare professionals, not a substitute for clinical judgment.
 
89
 
90
  # System message template for the agent
91
  SYSTEM_MESSAGE = """
92
+ You are an advanced Clinical Decision Support System for expert healthcare professionals, oncologists, and medical specialists.
93
+ Your primary purpose is to provide comprehensive, evidence-based clinical guidance strictly from authoritative medical guidelines using the tool "medical_guidelines_knowledge_tool".
94
+
95
+ **AUDIENCE**: Your responses are for practicing physicians, oncologists, and medical experts. Use appropriate medical terminology, clinical precision, and expert-level detail.
96
+
97
+ **RESPONSE STYLE**:
98
+ - Provide DETAILED, COMPREHENSIVE answers with clinical depth appropriate for specialists
99
+ - Use precise medical terminology without oversimplification
100
+ - Include specific clinical parameters, dosing regimens, biomarker thresholds, and staging details when available
101
+ - Reference specific tables, figures, algorithms, and flowcharts from guidelines
102
+ - Discuss nuances, clinical considerations, and evidence levels
103
+ - Compare different approaches when multiple options exist
104
+ - Highlight contraindications, special populations, and important clinical caveats
105
+
106
+ **CRITICAL INSTRUCTIONS - TOOL USAGE IS MANDATORY:**
107
+
108
+ **YOU MUST ALWAYS USE THE "medical_guidelines_knowledge_tool" FIRST FOR EVERY MEDICAL QUESTION.**
109
+ - Do NOT answer from your general knowledge or training data
110
+ - Do NOT provide information without first retrieving it from the guidelines
111
+ - ALWAYS call "medical_guidelines_knowledge_tool" before formulating your response
112
+ - Even for basic medical concepts (e.g., "what is a driver mutation"), you MUST retrieve information from the guidelines first
113
+ - Only after retrieving guideline information should you formulate your answer based on what was retrieved
114
+
115
+ **TOOL USAGE REQUIREMENTS:**
116
+ 1. **MEDICAL QUESTIONS** (definitions, treatments, guidelines, etc.):
117
+ - MANDATORY: Use "medical_guidelines_knowledge_tool" FIRST
118
+ - Then answer based ONLY on retrieved information
119
+
120
+ 2. **SIDE EFFECT REPORTING**: When a healthcare professional reports an adverse drug reaction, side effect, or medication-related complication:
121
+ - MANDATORY: Use "side_effect_recording_tool" first to document the information
122
+ - Return the tool's response directly to the user without modification
123
+ - DO NOT use validation or generate additional reports for side effect reporting queries
124
+ - Trigger phrases: "patient experienced", "side effect", "adverse reaction", "drug reaction", "medication caused", "developed after taking"
125
+
126
+ 3. **PROVIDER COMPARISON**: When comparing guidance between providers (e.g., "compare NCCN vs ESMO on ..."):
127
+ - MANDATORY: Use "compare_providers_tool" with appropriate `provider_a` and `provider_b` values
128
+
129
+ 4. **TIME/DATE QUERIES**: For current date/time or references like "today" or "now":
130
+ - MANDATORY: Use "get_current_datetime_tool"
131
+ - For every answer, you MUST provide COMPREHENSIVE citations including:
132
  * Source file name
133
+ * Page number(s) - including context pages if enriched content is provided
134
+ * Provider name (NCCN, ASCO, ESMO, NICE, etc.)
135
+ * Specific location (e.g., Table 1, Figure 2, Algorithm 3, Box 4, Section Header, etc.)
136
+ * Type of content (e.g., treatment algorithm, dosing table, biomarker criteria, staging flowchart, etc.)
137
+ * Evidence level or recommendation grade when available
138
+ - Use this format for detailed citations:
139
+ (Source: [file name], Pages: [page numbers], Provider: [provider name], Location: [specific location], Type: [content type], Evidence Level: [if available])
140
  - If multiple sources are used, cite each one with its corresponding metadata.
141
  - If a specific provider (NCCN, ASCO, ESMO, etc.) is mentioned in the question, prioritize information from that provider.
142
  - When citing tables or flowcharts:
143
+ * Specify the table/figure number and title
144
+ * Describe which specific rows, columns, or sections contain the relevant information
145
+ * Reference any relevant footnotes, legends, or annotations
146
+ * Include specific values, thresholds, or criteria mentioned
147
  - When citing text:
148
+ * Specify the section or subsection heading with full hierarchy
149
+ * Indicate if it's from a bullet point, paragraph, recommendation box, or other format
150
+ * Quote key phrases or specific recommendations when appropriate
151
+ - **ENRICHED CONTEXT**: When the retrieved content includes context pages (marked as "CONTEXT - Page X"), use this surrounding information to provide more complete clinical context and understanding
152
+
153
+ **IMPORTANT - NO GENERAL KNOWLEDGE RESPONSES:**
154
+ - If the answer is not found in the retrieved guidelines after using the tool, provide a helpful response that:
155
+ * Acknowledges the limitation: "I searched the available medical guidelines but could not find specific information about [topic]."
156
  * Suggests alternatives: "You may want to:
157
  - Rephrase your question with more specific clinical details
158
  - Specify a particular guideline provider (NCCN, ASCO, ESMO, NICE)
159
  - Consult the latest published guidelines directly for emerging topics"
160
  * Maintains professionalism: Never simply say "I don't know" - always provide context and next steps
161
+ - **NEVER answer from general knowledge or training data - ALWAYS use the tool first**
162
+ - Never speculate or provide information not present in the guidelines
163
+ - If the retrieved information is insufficient, acknowledge this and ask for clarification rather than supplementing with general knowledge
164
  - Always respond in English.
165
 
166
+ **FORMATTING FOR EXPERT AUDIENCE:**
167
+ - Use advanced markdown formatting for clinical clarity:
168
+ * Use **bold** for critical clinical points, drug names, and key recommendations
169
+ * Use bullet points and numbered lists for treatment sequences and decision algorithms
170
+ * Use tables to compare regimens, dosing schedules, or guideline differences
171
+ * Use headers (###) to organize complex responses by topic
172
+ * Use blockquotes (>) for direct guideline quotes or key recommendations
173
+ * Include specific numeric values, percentages, and statistical data when available
174
+ * Structure responses logically: Indication → Regimen → Dosing → Monitoring → Special Considerations
175
 
176
  **SAFETY DISCLAIMER:**
177
  Important: For emergencies call emergency services immediately. This is educational information for healthcare professionals, not a substitute for clinical judgment.
core/background_init.py CHANGED
@@ -51,8 +51,24 @@ class BackgroundInitializer:
51
  _ensure_initialized()
52
  self._update_progress("Retrievers initialized successfully", 90)
53
 
54
- # Step 3: Warm up LLM (optional, lightweight)
55
- self._update_progress("Warming up LLM...", 95)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
56
  from .config import get_llm
57
  llm = get_llm()
58
  self._update_progress("All components initialized successfully", 100)
 
51
  _ensure_initialized()
52
  self._update_progress("Retrievers initialized successfully", 90)
53
 
54
+ # Step 3: Learn medical terminology from corpus
55
+ self._update_progress("Learning medical terminology from corpus...", 92)
56
+ try:
57
+ from .medical_terminology import learn_from_corpus
58
+ from . import utils
59
+
60
+ # Load chunks to learn from
61
+ chunks = utils.load_chunks()
62
+ if chunks:
63
+ # Convert to format expected by learner
64
+ documents = [{'content': chunk.page_content} for chunk in chunks[:1000]] # Limit for performance
65
+ learn_from_corpus(documents)
66
+ logger.info(f"Learned medical terminology from {len(documents)} documents")
67
+ except Exception as e:
68
+ logger.warning(f"Could not learn terminology from corpus: {e}")
69
+
70
+ # Step 4: Warm up LLM (optional, lightweight)
71
+ self._update_progress("Warming up LLM...", 97)
72
  from .config import get_llm
73
  llm = get_llm()
74
  self._update_progress("All components initialized successfully", 100)
core/context_enrichment.py ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Context Enrichment Module for Medical RAG
3
+
4
+ This module enriches retrieved documents with surrounding context (adjacent pages)
5
+ to provide comprehensive information for expert medical professionals.
6
+ """
7
+
8
+ from typing import List, Dict, Set, Optional
9
+ from langchain.schema import Document
10
+ from pathlib import Path
11
+ from .config import logger
12
+
13
+
14
+ class ContextEnricher:
15
+ """
16
+ Enriches retrieved documents with surrounding pages for richer context.
17
+ """
18
+
19
+ def __init__(self, cache_size: int = 100):
20
+ """
21
+ Initialize context enricher with document cache.
22
+
23
+ Args:
24
+ cache_size: Maximum number of source documents to cache
25
+ """
26
+ self._document_cache: Dict[str, List[Document]] = {}
27
+ self._cache_size = cache_size
28
+
29
+ def enrich_documents(
30
+ self,
31
+ retrieved_docs: List[Document],
32
+ pages_before: int = 1,
33
+ pages_after: int = 1,
34
+ max_enriched_docs: int = 5
35
+ ) -> List[Document]:
36
+ """
37
+ Enrich retrieved documents by adding separate context pages.
38
+
39
+ Args:
40
+ retrieved_docs: List of retrieved documents
41
+ pages_before: Number of pages to include before each document
42
+ pages_after: Number of pages to include after each document
43
+ max_enriched_docs: Maximum number of documents to enrich (top results)
44
+
45
+ Returns:
46
+ List with original documents + separate context page documents
47
+ """
48
+ if not retrieved_docs:
49
+ return []
50
+
51
+ result_docs = []
52
+ processed_sources = set()
53
+ enriched_count = 0
54
+
55
+ # Only enrich top documents to avoid overwhelming context
56
+ docs_to_enrich = retrieved_docs[:max_enriched_docs]
57
+
58
+ for doc in docs_to_enrich:
59
+ try:
60
+ # Get source information
61
+ source = doc.metadata.get('source', 'unknown')
62
+ page_num = doc.metadata.get('page_number', 1)
63
+
64
+ # Skip if already processed this source-page combination
65
+ source_page_key = f"{source}_{page_num}"
66
+ if source_page_key in processed_sources:
67
+ continue
68
+
69
+ processed_sources.add(source_page_key)
70
+
71
+ # Get surrounding pages
72
+ surrounding_docs = self._get_surrounding_pages(
73
+ doc,
74
+ pages_before,
75
+ pages_after
76
+ )
77
+
78
+ if surrounding_docs:
79
+ # Add separate documents for each page
80
+ page_docs = self._create_separate_page_documents(
81
+ doc,
82
+ surrounding_docs,
83
+ pages_before,
84
+ pages_after
85
+ )
86
+ result_docs.extend(page_docs)
87
+ enriched_count += 1
88
+
89
+ # Log enrichment details
90
+ page_numbers = [int(d.metadata.get('page_number', 0)) for d in page_docs]
91
+ logger.debug(f"Enriched {source} page {page_num} with pages: {page_numbers}")
92
+ else:
93
+ # No surrounding pages found, add original with empty enrichment metadata
94
+ original_with_metadata = self._add_empty_enrichment_metadata(doc)
95
+ result_docs.append(original_with_metadata)
96
+
97
+ except Exception as e:
98
+ logger.warning(f"Could not enrich document from {doc.metadata.get('source')}: {e}")
99
+ original_with_metadata = self._add_empty_enrichment_metadata(doc)
100
+ result_docs.append(original_with_metadata)
101
+
102
+ # Add remaining documents without enrichment
103
+ for doc in retrieved_docs[max_enriched_docs:]:
104
+ original_with_metadata = self._add_empty_enrichment_metadata(doc)
105
+ result_docs.append(original_with_metadata)
106
+
107
+ logger.info(f"Enriched {enriched_count} documents with surrounding context pages")
108
+ return result_docs
109
+
110
+ def _get_surrounding_pages(
111
+ self,
112
+ doc: Document,
113
+ pages_before: int,
114
+ pages_after: int
115
+ ) -> List[Document]:
116
+ """
117
+ Get surrounding pages for a document.
118
+
119
+ Args:
120
+ doc: Original document
121
+ pages_before: Number of pages before
122
+ pages_after: Number of pages after
123
+
124
+ Returns:
125
+ List of surrounding documents (including original), deduplicated by page number
126
+ """
127
+ source = doc.metadata.get('source', 'unknown')
128
+ page_num = doc.metadata.get('page_number', 1)
129
+ provider = doc.metadata.get('provider', 'unknown')
130
+ disease = doc.metadata.get('disease', 'unknown')
131
+
132
+ # Try to get full document from cache or load it
133
+ full_doc_pages = self._get_full_document(source, provider, disease)
134
+
135
+ if not full_doc_pages:
136
+ return []
137
+
138
+ # Find the target page and surrounding pages
139
+ target_page = int(page_num) if isinstance(page_num, (int, str)) else 1
140
+
141
+ # Use a dict to deduplicate by page number (keep first occurrence)
142
+ pages_dict = {}
143
+
144
+ for page_doc in full_doc_pages:
145
+ doc_page_num = page_doc.metadata.get('page_number', 0)
146
+ if isinstance(doc_page_num, str):
147
+ try:
148
+ doc_page_num = int(doc_page_num)
149
+ except:
150
+ continue
151
+
152
+ # Include pages within range
153
+ if target_page - pages_before <= doc_page_num <= target_page + pages_after:
154
+ # Only add if not already present (deduplication)
155
+ if doc_page_num not in pages_dict:
156
+ pages_dict[doc_page_num] = page_doc
157
+
158
+ # Return sorted by page number
159
+ surrounding = [pages_dict[pn] for pn in sorted(pages_dict.keys())]
160
+
161
+ return surrounding
162
+
163
+ def _get_full_document(
164
+ self,
165
+ source: str,
166
+ provider: str,
167
+ disease: str
168
+ ) -> Optional[List[Document]]:
169
+ """
170
+ Get full document pages from chunks cache.
171
+
172
+ Args:
173
+ source: Source filename
174
+ provider: Provider name
175
+ disease: Disease name
176
+
177
+ Returns:
178
+ List of all pages in the document, or None if not found
179
+ """
180
+ cache_key = f"{provider}_{disease}_{source}"
181
+
182
+ # Check cache
183
+ if cache_key in self._document_cache:
184
+ return self._document_cache[cache_key]
185
+
186
+ # Load from chunks cache instead of trying to reload PDFs
187
+ try:
188
+ from . import utils
189
+
190
+ # Load all chunks
191
+ all_chunks = utils.load_chunks()
192
+ if not all_chunks:
193
+ logger.debug(f"No chunks available for enrichment")
194
+ return None
195
+
196
+ # Filter chunks for this specific document
197
+ doc_pages = []
198
+ for chunk in all_chunks:
199
+ chunk_source = chunk.metadata.get('source', '')
200
+ chunk_provider = chunk.metadata.get('provider', '')
201
+ chunk_disease = chunk.metadata.get('disease', '')
202
+
203
+ # Match by source, provider, and disease
204
+ if (chunk_source == source and
205
+ chunk_provider == provider and
206
+ chunk_disease == disease):
207
+ doc_pages.append(chunk)
208
+
209
+ if not doc_pages:
210
+ logger.debug(f"Could not find chunks for document: {source} (Provider: {provider}, Disease: {disease})")
211
+ return None
212
+
213
+ # Sort by page number
214
+ doc_pages.sort(key=lambda d: int(d.metadata.get('page_number', 0)))
215
+
216
+ # Cache it (with size limit)
217
+ if len(self._document_cache) >= self._cache_size:
218
+ # Remove oldest entry
219
+ self._document_cache.pop(next(iter(self._document_cache)))
220
+
221
+ self._document_cache[cache_key] = doc_pages
222
+ logger.debug(f"Loaded {len(doc_pages)} pages for {source} from chunks cache")
223
+ return doc_pages
224
+
225
+ except Exception as e:
226
+ logger.warning(f"Error loading document from chunks cache {source}: {e}")
227
+ return None
228
+
229
+ def _create_separate_page_documents(
230
+ self,
231
+ original_doc: Document,
232
+ surrounding_docs: List[Document],
233
+ pages_before: int,
234
+ pages_after: int
235
+ ) -> List[Document]:
236
+ """
237
+ Create separate document objects for original page and context pages.
238
+
239
+ Args:
240
+ original_doc: Original retrieved document
241
+ surrounding_docs: List of surrounding documents
242
+ pages_before: Number of pages before
243
+ pages_after: Number of pages after
244
+
245
+ Returns:
246
+ List of separate documents (context pages + original page + context pages)
247
+ """
248
+ # Sort by page number
249
+ sorted_docs = sorted(
250
+ surrounding_docs,
251
+ key=lambda d: int(d.metadata.get('page_number', 0))
252
+ )
253
+
254
+ original_page = int(original_doc.metadata.get('page_number', 1))
255
+ result_docs = []
256
+
257
+ for doc in sorted_docs:
258
+ page_num = int(doc.metadata.get('page_number', 0))
259
+
260
+ # Determine if this is a context page or the original page
261
+ is_context_page = (page_num != original_page)
262
+
263
+ # Create document with appropriate metadata
264
+ page_doc = Document(
265
+ page_content=doc.page_content,
266
+ metadata={
267
+ **doc.metadata,
268
+ 'context_enrichment': is_context_page,
269
+ 'enriched': False,
270
+ 'pages_included': [],
271
+ 'primary_page': None,
272
+ 'context_pages_before': None,
273
+ 'context_pages_after': None,
274
+ }
275
+ )
276
+
277
+ result_docs.append(page_doc)
278
+
279
+ return result_docs
280
+
281
+ def _add_empty_enrichment_metadata(self, doc: Document) -> Document:
282
+ """
283
+ Add empty enrichment metadata fields to a document.
284
+
285
+ Args:
286
+ doc: Original document
287
+
288
+ Returns:
289
+ Document with enrichment metadata fields set to default values
290
+ """
291
+ return Document(
292
+ page_content=doc.page_content,
293
+ metadata={
294
+ **doc.metadata,
295
+ 'enriched': False,
296
+ 'pages_included': [],
297
+ 'primary_page': None,
298
+ 'context_pages_before': None,
299
+ 'context_pages_after': None,
300
+ }
301
+ )
302
+
303
+
304
+ # Global enricher instance
305
+ _context_enricher = ContextEnricher(cache_size=100)
306
+
307
+
308
+ def enrich_retrieved_documents(
309
+ documents: List[Document],
310
+ pages_before: int = 1,
311
+ pages_after: int = 1,
312
+ max_enriched: int = 5
313
+ ) -> List[Document]:
314
+ """
315
+ Convenience function to enrich retrieved documents.
316
+
317
+ Args:
318
+ documents: Retrieved documents
319
+ pages_before: Number of pages to include before each document
320
+ pages_after: Number of pages to include after each document
321
+ max_enriched: Maximum number of documents to enrich
322
+
323
+ Returns:
324
+ Enriched documents with surrounding context
325
+ """
326
+ return _context_enricher.enrich_documents(
327
+ documents,
328
+ pages_before=pages_before,
329
+ pages_after=pages_after,
330
+ max_enriched_docs=max_enriched
331
+ )
332
+
333
+
334
+ def get_context_enricher() -> ContextEnricher:
335
+ """Get the global context enricher instance."""
336
+ return _context_enricher
core/github_storage.py CHANGED
@@ -201,10 +201,10 @@ class GitHubStorage:
201
 
202
  def save_validation_results(self, evaluation_data: Dict[str, Any]) -> bool:
203
  """
204
- Save validation results to GitHub repository as JSON with unique ID generation
205
 
206
  Args:
207
- evaluation_data: Dictionary containing evaluation data
208
 
209
  Returns:
210
  True if successful, False otherwise
@@ -222,31 +222,16 @@ class GitHubStorage:
222
  if not isinstance(evaluations, list):
223
  evaluations = []
224
  except json.JSONDecodeError:
 
225
  evaluations = []
226
  else:
227
  evaluations = []
228
 
229
- # Generate unique interaction ID
230
- existing_ids = set()
231
- for eval_item in evaluations:
232
- existing_id = eval_item.get("interaction_id")
233
- if existing_id:
234
- try:
235
- existing_ids.add(int(existing_id))
236
- except (ValueError, TypeError):
237
- # If ID is not numeric, add as string
238
- existing_ids.add(existing_id)
239
-
240
- # Find next available numeric ID
241
- next_id = 1
242
- while next_id in existing_ids:
243
- next_id += 1
244
-
245
- # Update the evaluation data with unique ID
246
- evaluation_data["interaction_id"] = str(next_id)
247
- logger.info(f"Assigned unique interaction ID: {next_id}")
248
-
249
- # Add new evaluation
250
  evaluations.append(evaluation_data)
251
 
252
  # Convert to JSON string
@@ -258,7 +243,12 @@ class GitHubStorage:
258
  # Upload file
259
  commit_message = f"Add validation results for interaction {evaluation_data.get('interaction_id', 'unknown')} - {evaluation_data.get('timestamp', 'unknown time')}"
260
 
261
- return self._upload_file(file_path, json_content, commit_message, sha)
 
 
 
 
 
262
 
263
  except Exception as e:
264
  logger.error(f"Error saving validation results to GitHub: {e}")
 
201
 
202
  def save_validation_results(self, evaluation_data: Dict[str, Any]) -> bool:
203
  """
204
+ Save validation results to GitHub repository as JSON
205
 
206
  Args:
207
+ evaluation_data: Dictionary containing evaluation data with interaction_id already set
208
 
209
  Returns:
210
  True if successful, False otherwise
 
222
  if not isinstance(evaluations, list):
223
  evaluations = []
224
  except json.JSONDecodeError:
225
+ logger.warning("Failed to parse existing evaluation_results.json, starting fresh")
226
  evaluations = []
227
  else:
228
  evaluations = []
229
 
230
+ # Log the current state
231
+ logger.info(f"Loading existing evaluations: {len(evaluations)} found")
232
+ logger.info(f"Adding new evaluation with ID: {evaluation_data.get('interaction_id', 'unknown')}")
233
+
234
+ # Add new evaluation to the list
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  evaluations.append(evaluation_data)
236
 
237
  # Convert to JSON string
 
243
  # Upload file
244
  commit_message = f"Add validation results for interaction {evaluation_data.get('interaction_id', 'unknown')} - {evaluation_data.get('timestamp', 'unknown time')}"
245
 
246
+ success = self._upload_file(file_path, json_content, commit_message, sha)
247
+
248
+ if success:
249
+ logger.info(f"Successfully saved evaluation. Total evaluations now: {len(evaluations)}")
250
+
251
+ return success
252
 
253
  except Exception as e:
254
  logger.error(f"Error saving validation results to GitHub: {e}")
core/medical_terminology.py ADDED
@@ -0,0 +1,506 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Medical Terminology Module with Dynamic Learning
3
+
4
+ This module provides intelligent handling of medical linguistic variability including:
5
+ - Synonyms and alternate terms
6
+ - Abbreviations and acronyms (with context awareness)
7
+ - Regional spelling variations (US/UK/International)
8
+ - Specialty-specific terminology
9
+ - Dynamic learning from corpus
10
+ """
11
+
12
+ import re
13
+ import json
14
+ from typing import List, Dict, Set, Tuple, Optional
15
+ from collections import defaultdict
16
+ from pathlib import Path
17
+ from .config import logger
18
+
19
+ # ============================================================================
20
+ # CORE MEDICAL TERMINOLOGY MAPPINGS
21
+ # ============================================================================
22
+
23
+ # Common medical abbreviations with context-aware expansions
24
+ MEDICAL_ABBREVIATIONS = {
25
+ # Cancer Types
26
+ "nsclc": ["non-small cell lung cancer", "non small cell lung cancer"],
27
+ "sclc": ["small cell lung cancer"],
28
+ "nscl": ["non-small cell lung"],
29
+ "alk": ["anaplastic lymphoma kinase"],
30
+ "egfr": ["epidermal growth factor receptor"],
31
+ "ros1": ["ros proto-oncogene 1", "c-ros oncogene 1"],
32
+ "braf": ["b-raf proto-oncogene"],
33
+ "kras": ["kirsten rat sarcoma viral oncogene"],
34
+ "met": ["mesenchymal epithelial transition", "met proto-oncogene"],
35
+ "her2": ["human epidermal growth factor receptor 2"],
36
+ "ret": ["ret proto-oncogene", "rearranged during transfection"],
37
+ "ntrk": ["neurotrophic tyrosine receptor kinase", "neurotrophic tropomyosin receptor kinase"],
38
+
39
+ # Treatment & Procedures
40
+ "chemo": ["chemotherapy"],
41
+ "rt": ["radiation therapy", "radiotherapy"],
42
+ "sbrt": ["stereotactic body radiation therapy", "stereotactic body radiotherapy"],
43
+ "imrt": ["intensity-modulated radiation therapy"],
44
+ "ct": ["computed tomography", "ct scan"],
45
+ "pet": ["positron emission tomography"],
46
+ "mri": ["magnetic resonance imaging"],
47
+ "io": ["immunotherapy", "immune-oncology"],
48
+ "ici": ["immune checkpoint inhibitor", "immune checkpoint inhibitors"],
49
+ "tki": ["tyrosine kinase inhibitor", "tyrosine kinase inhibitors"],
50
+ "pd-1": ["programmed death-1", "programmed cell death protein 1"],
51
+ "pd-l1": ["programmed death-ligand 1"],
52
+ "ctla-4": ["cytotoxic t-lymphocyte-associated protein 4"],
53
+
54
+ # Clinical Terms
55
+ "os": ["overall survival"],
56
+ "pfs": ["progression-free survival"],
57
+ "dfs": ["disease-free survival"],
58
+ "orr": ["overall response rate", "objective response rate"],
59
+ "cr": ["complete response"],
60
+ "pr": ["partial response"],
61
+ "sd": ["stable disease"],
62
+ "pd": ["progressive disease"],
63
+ "ecog": ["eastern cooperative oncology group"],
64
+ "ps": ["performance status"],
65
+ "aes": ["adverse events"],
66
+ "sae": ["serious adverse event", "serious adverse events"],
67
+ "qol": ["quality of life"],
68
+
69
+ # Staging
70
+ "tnm": ["tumor node metastasis", "tnm staging"],
71
+ "ajcc": ["american joint committee on cancer"],
72
+
73
+ # Drugs (common abbreviations)
74
+ "cddp": ["cisplatin"],
75
+ "cbdca": ["carboplatin"],
76
+ "pem": ["pemetrexed"],
77
+ "gem": ["gemcitabine"],
78
+ "doc": ["docetaxel"],
79
+ "pac": ["paclitaxel"],
80
+ "vin": ["vinorelbine"],
81
+ "eto": ["etoposide"],
82
+ }
83
+
84
+ # Synonym mappings for medical terms
85
+ MEDICAL_SYNONYMS = {
86
+ # Cancer terminology
87
+ "lung cancer": ["pulmonary cancer", "lung carcinoma", "pulmonary carcinoma", "bronchogenic carcinoma"],
88
+ "non-small cell lung cancer": ["nsclc", "non small cell lung cancer", "non-small-cell lung cancer"],
89
+ "small cell lung cancer": ["sclc", "small-cell lung cancer", "oat cell carcinoma"],
90
+ "adenocarcinoma": ["adeno", "glandular cancer"],
91
+ "squamous cell carcinoma": ["squamous carcinoma", "scc", "epidermoid carcinoma"],
92
+ "metastatic": ["advanced", "stage iv", "stage 4", "metastases", "mets"],
93
+ "locally advanced": ["stage iii", "stage 3", "regional spread"],
94
+ "early stage": ["stage i", "stage ii", "stage 1", "stage 2", "localized"],
95
+
96
+ # Treatment terms
97
+ "chemotherapy": ["chemo", "cytotoxic therapy", "systemic therapy"],
98
+ "radiation therapy": ["radiotherapy", "rt", "radiation treatment", "irradiation"],
99
+ "immunotherapy": ["immune therapy", "io", "immune-oncology", "checkpoint inhibitor"],
100
+ "targeted therapy": ["molecular therapy", "precision medicine", "targeted treatment"],
101
+ "surgery": ["surgical resection", "resection", "operative treatment", "surgical intervention"],
102
+ "lobectomy": ["lobe resection", "pulmonary lobectomy"],
103
+ "pneumonectomy": ["lung removal", "complete lung resection"],
104
+ "wedge resection": ["segmentectomy", "limited resection"],
105
+
106
+ # Molecular markers
107
+ "mutation": ["alteration", "variant", "genetic change", "molecular alteration"],
108
+ "biomarker": ["molecular marker", "tumor marker", "genetic marker"],
109
+ "driver mutation": ["oncogenic driver", "actionable mutation", "targetable mutation"],
110
+
111
+ # Clinical outcomes
112
+ "survival": ["survival rate", "survival outcome"],
113
+ "response": ["treatment response", "tumor response", "clinical response"],
114
+ "progression": ["disease progression", "tumor progression", "cancer progression"],
115
+ "recurrence": ["relapse", "disease recurrence", "tumor recurrence"],
116
+ "remission": ["response", "disease control"],
117
+
118
+ # Side effects
119
+ "adverse event": ["side effect", "adverse reaction", "toxicity", "adverse drug reaction"],
120
+ "neutropenia": ["low white blood cell count", "low neutrophil count"],
121
+ "anemia": ["low red blood cell count", "low hemoglobin"],
122
+ "thrombocytopenia": ["low platelet count"],
123
+ "nausea": ["feeling sick", "queasiness"],
124
+ "fatigue": ["tiredness", "exhaustion", "weakness"],
125
+
126
+ # Diagnostic terms
127
+ "biopsy": ["tissue sample", "tissue sampling"],
128
+ "imaging": ["radiology", "diagnostic imaging", "medical imaging"],
129
+ "screening": ["early detection", "cancer screening"],
130
+ }
131
+
132
+ # Regional spelling variations (US/UK/International)
133
+ SPELLING_VARIATIONS = {
134
+ # US -> UK/International variants
135
+ "tumor": ["tumour"],
136
+ "tumors": ["tumours"],
137
+ "metastasis": ["metastases"],
138
+ "anemia": ["anaemia"],
139
+ "edema": ["oedema"],
140
+ "esophageal": ["oesophageal"],
141
+ "pediatric": ["paediatric"],
142
+ "hematology": ["haematology"],
143
+ "hemoglobin": ["haemoglobin"],
144
+ "leukemia": ["leukaemia"],
145
+ "lymphoma": ["lymphoma"], # Same in both
146
+ "optimize": ["optimise"],
147
+ "randomized": ["randomised"],
148
+ "analyze": ["analyse"],
149
+ "center": ["centre"],
150
+ "fiber": ["fibre"],
151
+ }
152
+
153
+ # Context-dependent abbreviations (require disambiguation)
154
+ CONTEXT_DEPENDENT_ABBREVS = {
155
+ "ca": {
156
+ "cancer": ["cancer", "carcinoma"],
157
+ "calcium": ["calcium"],
158
+ },
159
+ "cr": {
160
+ "complete_response": ["complete response", "complete remission"],
161
+ "creatinine": ["creatinine"],
162
+ },
163
+ "pt": {
164
+ "patient": ["patient"],
165
+ "prothrombin_time": ["prothrombin time"],
166
+ },
167
+ "rt": {
168
+ "radiation_therapy": ["radiation therapy", "radiotherapy"],
169
+ "reverse_transcriptase": ["reverse transcriptase"],
170
+ },
171
+ }
172
+
173
+ # ============================================================================
174
+ # DYNAMIC LEARNING COMPONENTS
175
+ # ============================================================================
176
+
177
+ class MedicalTerminologyLearner:
178
+ """
179
+ Dynamically learns medical term variations from the corpus.
180
+ Builds co-occurrence patterns and semantic relationships.
181
+ """
182
+
183
+ def __init__(self, cache_path: Optional[str] = None):
184
+ self.cache_path = cache_path or "data/medical_terms_cache.json"
185
+ self.term_cooccurrence = defaultdict(lambda: defaultdict(int))
186
+ self.learned_synonyms = defaultdict(set)
187
+ self.learned_abbreviations = defaultdict(set)
188
+ self.context_patterns = defaultdict(list)
189
+ self._load_cache()
190
+
191
+ def _load_cache(self):
192
+ """Load previously learned terms from cache"""
193
+ try:
194
+ cache_file = Path(self.cache_path)
195
+ if cache_file.exists():
196
+ with open(cache_file, 'r', encoding='utf-8') as f:
197
+ data = json.load(f)
198
+ self.learned_synonyms = defaultdict(set, {k: set(v) for k, v in data.get('synonyms', {}).items()})
199
+ self.learned_abbreviations = defaultdict(set, {k: set(v) for k, v in data.get('abbreviations', {}).items()})
200
+ logger.info(f"Loaded {len(self.learned_synonyms)} learned synonyms from cache")
201
+ except Exception as e:
202
+ logger.warning(f"Could not load term cache: {e}")
203
+
204
+ def _save_cache(self):
205
+ """Save learned terms to cache"""
206
+ try:
207
+ cache_file = Path(self.cache_path)
208
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
209
+ data = {
210
+ 'synonyms': {k: list(v) for k, v in self.learned_synonyms.items()},
211
+ 'abbreviations': {k: list(v) for k, v in self.learned_abbreviations.items()}
212
+ }
213
+ with open(cache_file, 'w', encoding='utf-8') as f:
214
+ json.dump(data, f, indent=2)
215
+ logger.info(f"Saved learned terms to cache")
216
+ except Exception as e:
217
+ logger.warning(f"Could not save term cache: {e}")
218
+
219
+ def learn_from_documents(self, documents: List[Dict[str, str]]):
220
+ """
221
+ Learn term variations from a corpus of documents.
222
+ Identifies patterns like:
223
+ - "X (Y)" -> Y is abbreviation of X
224
+ - "X, also known as Y" -> X and Y are synonyms
225
+ - "X or Y" in similar contexts -> potential synonyms
226
+ """
227
+ for doc in documents:
228
+ content = doc.get('content', '')
229
+ self._extract_abbreviation_patterns(content)
230
+ self._extract_synonym_patterns(content)
231
+ self._build_cooccurrence(content)
232
+
233
+ self._save_cache()
234
+
235
+ def _extract_abbreviation_patterns(self, text: str):
236
+ """Extract abbreviations from patterns like 'Full Term (ABBR)'"""
237
+ # Pattern: "Full Term (ABBR)" or "Full Term [ABBR]"
238
+ pattern = r'([A-Z][a-z]+(?:\s+[A-Z]?[a-z]+)*)\s*[\(\[]([A-Z]{2,}|[A-Z][a-z]*(?:-[A-Z][a-z]*)*)[\)\]]'
239
+ matches = re.finditer(pattern, text)
240
+
241
+ for match in matches:
242
+ full_term = match.group(1).strip().lower()
243
+ abbrev = match.group(2).strip().lower()
244
+
245
+ # Validate: abbreviation should be shorter and contain initials
246
+ if len(abbrev) < len(full_term) and len(abbrev) >= 2:
247
+ self.learned_abbreviations[abbrev].add(full_term)
248
+ logger.debug(f"Learned: {abbrev} -> {full_term}")
249
+
250
+ def _extract_synonym_patterns(self, text: str):
251
+ """Extract synonyms from patterns like 'X, also known as Y' or 'X (Y)'"""
252
+ # Pattern: "X, also known as Y" or "X, also called Y"
253
+ patterns = [
254
+ r'([a-z\s\-]+),?\s+also\s+known\s+as\s+([a-z\s\-]+)',
255
+ r'([a-z\s\-]+),?\s+also\s+called\s+([a-z\s\-]+)',
256
+ r'([a-z\s\-]+)\s+\(([a-z\s\-]+)\)',
257
+ ]
258
+
259
+ for pattern in patterns:
260
+ matches = re.finditer(pattern, text.lower())
261
+ for match in matches:
262
+ term1 = match.group(1).strip()
263
+ term2 = match.group(2).strip()
264
+
265
+ # Validate: both should be reasonable length
266
+ if 3 <= len(term1) <= 50 and 3 <= len(term2) <= 50:
267
+ self.learned_synonyms[term1].add(term2)
268
+ self.learned_synonyms[term2].add(term1)
269
+
270
+ def _build_cooccurrence(self, text: str):
271
+ """Build co-occurrence matrix for terms"""
272
+ # Extract medical terms (simplified)
273
+ terms = re.findall(r'\b[a-z]{3,}(?:\s+[a-z]{3,}){0,3}\b', text.lower())
274
+
275
+ # Build co-occurrence within a window
276
+ window_size = 10
277
+ for i, term in enumerate(terms):
278
+ for j in range(max(0, i - window_size), min(len(terms), i + window_size + 1)):
279
+ if i != j:
280
+ self.term_cooccurrence[term][terms[j]] += 1
281
+
282
+ def get_related_terms(self, term: str, threshold: int = 3) -> Set[str]:
283
+ """Get terms that frequently co-occur with the given term"""
284
+ term_lower = term.lower()
285
+ related = set()
286
+
287
+ if term_lower in self.term_cooccurrence:
288
+ for related_term, count in self.term_cooccurrence[term_lower].items():
289
+ if count >= threshold:
290
+ related.add(related_term)
291
+
292
+ return related
293
+
294
+ # Global learner instance
295
+ _terminology_learner = MedicalTerminologyLearner()
296
+
297
+ # ============================================================================
298
+ # QUERY NORMALIZATION AND EXPANSION FUNCTIONS
299
+ # ============================================================================
300
+
301
+ def normalize_query(query: str) -> str:
302
+ """
303
+ Normalize a query by:
304
+ - Converting to lowercase
305
+ - Removing extra whitespace
306
+ - Standardizing punctuation
307
+ """
308
+ # Convert to lowercase
309
+ normalized = query.lower()
310
+
311
+ # Standardize hyphens and dashes
312
+ normalized = re.sub(r'[–—]', '-', normalized)
313
+
314
+ # Remove extra whitespace
315
+ normalized = re.sub(r'\s+', ' ', normalized).strip()
316
+
317
+ return normalized
318
+
319
+
320
+ def expand_abbreviations(text: str, context: Optional[str] = None) -> List[str]:
321
+ """
322
+ Expand abbreviations in text to their full forms.
323
+ Uses context when available for disambiguation.
324
+ """
325
+ expansions = [text]
326
+ text_lower = text.lower()
327
+
328
+ # Check learned abbreviations first
329
+ for abbrev, full_forms in _terminology_learner.learned_abbreviations.items():
330
+ if abbrev in text_lower:
331
+ for full_form in full_forms:
332
+ expanded = text_lower.replace(abbrev, full_form)
333
+ if expanded != text_lower:
334
+ expansions.append(expanded)
335
+
336
+ # Check predefined abbreviations
337
+ for abbrev, full_forms in MEDICAL_ABBREVIATIONS.items():
338
+ if re.search(rf'\b{re.escape(abbrev)}\b', text_lower):
339
+ for full_form in full_forms:
340
+ expanded = re.sub(rf'\b{re.escape(abbrev)}\b', full_form, text_lower)
341
+ if expanded != text_lower:
342
+ expansions.append(expanded)
343
+
344
+ # Remove duplicates while preserving order
345
+ seen = set()
346
+ unique_expansions = []
347
+ for exp in expansions:
348
+ if exp not in seen:
349
+ seen.add(exp)
350
+ unique_expansions.append(exp)
351
+
352
+ return unique_expansions
353
+
354
+
355
+ def get_synonyms(term: str) -> Set[str]:
356
+ """Get all known synonyms for a medical term"""
357
+ term_lower = term.lower()
358
+ synonyms = set()
359
+
360
+ # Check predefined synonyms
361
+ if term_lower in MEDICAL_SYNONYMS:
362
+ synonyms.update(MEDICAL_SYNONYMS[term_lower])
363
+
364
+ # Check if term is a synonym of something else
365
+ for key, syn_list in MEDICAL_SYNONYMS.items():
366
+ if term_lower in syn_list:
367
+ synonyms.add(key)
368
+ synonyms.update(syn_list)
369
+
370
+ # Check learned synonyms
371
+ if term_lower in _terminology_learner.learned_synonyms:
372
+ synonyms.update(_terminology_learner.learned_synonyms[term_lower])
373
+
374
+ # Remove the original term
375
+ synonyms.discard(term_lower)
376
+
377
+ return synonyms
378
+
379
+
380
+ def get_spelling_variations(term: str) -> Set[str]:
381
+ """Get regional spelling variations for a term"""
382
+ term_lower = term.lower()
383
+ variations = set()
384
+
385
+ # Check direct mapping
386
+ if term_lower in SPELLING_VARIATIONS:
387
+ variations.update(SPELLING_VARIATIONS[term_lower])
388
+
389
+ # Check reverse mapping
390
+ for key, var_list in SPELLING_VARIATIONS.items():
391
+ if term_lower in var_list:
392
+ variations.add(key)
393
+ variations.update(var_list)
394
+
395
+ variations.discard(term_lower)
396
+ return variations
397
+
398
+
399
+ def extract_medical_entities(text: str) -> List[Tuple[str, str]]:
400
+ """
401
+ Extract medical entities from text.
402
+ Returns list of (entity, type) tuples.
403
+ """
404
+ entities = []
405
+ text_lower = text.lower()
406
+
407
+ # Extract abbreviations
408
+ for abbrev in MEDICAL_ABBREVIATIONS.keys():
409
+ if re.search(rf'\b{re.escape(abbrev)}\b', text_lower):
410
+ entities.append((abbrev, 'abbreviation'))
411
+
412
+ # Extract known medical terms
413
+ for term in MEDICAL_SYNONYMS.keys():
414
+ if term in text_lower:
415
+ entities.append((term, 'medical_term'))
416
+
417
+ return entities
418
+
419
+
420
+ def is_medical_abbreviation(text: str) -> bool:
421
+ """Check if text is a known medical abbreviation"""
422
+ text_lower = text.lower().strip()
423
+ return text_lower in MEDICAL_ABBREVIATIONS or text_lower in _terminology_learner.learned_abbreviations
424
+
425
+
426
+ def get_abbreviation_expansion(abbrev: str) -> List[str]:
427
+ """Get all possible expansions for an abbreviation"""
428
+ abbrev_lower = abbrev.lower().strip()
429
+ expansions = []
430
+
431
+ # Check predefined
432
+ if abbrev_lower in MEDICAL_ABBREVIATIONS:
433
+ expansions.extend(MEDICAL_ABBREVIATIONS[abbrev_lower])
434
+
435
+ # Check learned
436
+ if abbrev_lower in _terminology_learner.learned_abbreviations:
437
+ expansions.extend(_terminology_learner.learned_abbreviations[abbrev_lower])
438
+
439
+ return expansions
440
+
441
+
442
+ def expand_query_with_variations(query: str, max_variations: int = 5) -> List[str]:
443
+ """
444
+ Generate query variations by expanding abbreviations, adding synonyms,
445
+ and including spelling variations.
446
+
447
+ Args:
448
+ query: Original query string
449
+ max_variations: Maximum number of variations to generate
450
+
451
+ Returns:
452
+ List of query variations including the original
453
+ """
454
+ variations = [query]
455
+ query_lower = normalize_query(query)
456
+
457
+ # 1. Expand abbreviations
458
+ abbrev_expansions = expand_abbreviations(query_lower)
459
+ variations.extend(abbrev_expansions)
460
+
461
+ # 2. Add synonym variations
462
+ words = query_lower.split()
463
+ for i, word in enumerate(words):
464
+ synonyms = get_synonyms(word)
465
+ for syn in list(synonyms)[:2]: # Limit to 2 synonyms per word
466
+ new_query = ' '.join(words[:i] + [syn] + words[i+1:])
467
+ variations.append(new_query)
468
+
469
+ # 3. Add spelling variations
470
+ for word in words:
471
+ spelling_vars = get_spelling_variations(word)
472
+ for var in spelling_vars:
473
+ new_query = query_lower.replace(word, var)
474
+ variations.append(new_query)
475
+
476
+ # 4. Add multi-word phrase variations
477
+ for term, synonyms in MEDICAL_SYNONYMS.items():
478
+ if term in query_lower:
479
+ for syn in list(synonyms)[:2]:
480
+ new_query = query_lower.replace(term, syn)
481
+ variations.append(new_query)
482
+
483
+ # Remove duplicates and limit
484
+ seen = set()
485
+ unique_variations = []
486
+ for var in variations:
487
+ if var not in seen:
488
+ seen.add(var)
489
+ unique_variations.append(var)
490
+ if len(unique_variations) >= max_variations:
491
+ break
492
+
493
+ return unique_variations
494
+
495
+
496
+ def learn_from_corpus(documents: List[Dict[str, str]]):
497
+ """
498
+ Learn medical term variations from a corpus of documents.
499
+ Should be called during system initialization.
500
+ """
501
+ _terminology_learner.learn_from_documents(documents)
502
+
503
+
504
+ def get_terminology_learner() -> MedicalTerminologyLearner:
505
+ """Get the global terminology learner instance"""
506
+ return _terminology_learner
core/query_expansion.py ADDED
@@ -0,0 +1,432 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Query Expansion Module for Medical Linguistic Variability
3
+
4
+ This module provides intelligent query expansion to handle:
5
+ - Medical term variations and synonyms
6
+ - Abbreviation expansion
7
+ - Spelling variations (US/UK/International)
8
+ - Specialty-specific terminology
9
+ - Multi-query retrieval strategies
10
+ """
11
+
12
+ import re
13
+ from typing import List, Dict, Set, Tuple, Optional
14
+ from langchain.schema import Document
15
+ from .medical_terminology import (
16
+ normalize_query,
17
+ expand_query_with_variations,
18
+ get_synonyms,
19
+ expand_abbreviations,
20
+ extract_medical_entities,
21
+ is_medical_abbreviation,
22
+ get_abbreviation_expansion,
23
+ )
24
+ from .config import logger
25
+
26
+
27
+ class QueryExpansionStrategy:
28
+ """
29
+ Intelligent query expansion strategy that adapts based on query characteristics.
30
+ """
31
+
32
+ def __init__(self):
33
+ self.expansion_cache = {}
34
+
35
+ def expand(self, query: str, strategy: str = "adaptive") -> List[str]:
36
+ """
37
+ Expand query using specified strategy.
38
+
39
+ Args:
40
+ query: Original query string
41
+ strategy: Expansion strategy - "adaptive", "aggressive", "conservative", "abbreviation_focused"
42
+
43
+ Returns:
44
+ List of expanded query variations
45
+ """
46
+ # Check cache
47
+ cache_key = f"{query}_{strategy}"
48
+ if cache_key in self.expansion_cache:
49
+ return self.expansion_cache[cache_key]
50
+
51
+ if strategy == "adaptive":
52
+ expansions = self._adaptive_expansion(query)
53
+ elif strategy == "aggressive":
54
+ expansions = self._aggressive_expansion(query)
55
+ elif strategy == "conservative":
56
+ expansions = self._conservative_expansion(query)
57
+ elif strategy == "abbreviation_focused":
58
+ expansions = self._abbreviation_focused_expansion(query)
59
+ else:
60
+ expansions = [query]
61
+
62
+ # Cache result
63
+ self.expansion_cache[cache_key] = expansions
64
+ return expansions
65
+
66
+ def _adaptive_expansion(self, query: str) -> List[str]:
67
+ """
68
+ Adaptive expansion that adjusts based on query characteristics.
69
+ - Short queries (< 5 words): More aggressive expansion
70
+ - Long queries: More conservative
71
+ - Queries with abbreviations: Focus on abbreviation expansion
72
+ """
73
+ words = query.split()
74
+ word_count = len(words)
75
+
76
+ # Detect if query contains abbreviations
77
+ has_abbrev = any(is_medical_abbreviation(word) for word in words)
78
+
79
+ if has_abbrev:
80
+ # Focus on abbreviation expansion
81
+ return self._abbreviation_focused_expansion(query)
82
+ elif word_count <= 3:
83
+ # Short query - aggressive expansion
84
+ return self._aggressive_expansion(query)
85
+ elif word_count <= 7:
86
+ # Medium query - balanced expansion
87
+ return expand_query_with_variations(query, max_variations=5)
88
+ else:
89
+ # Long query - conservative expansion
90
+ return self._conservative_expansion(query)
91
+
92
+ def _aggressive_expansion(self, query: str) -> List[str]:
93
+ """
94
+ Aggressive expansion with more variations.
95
+ Useful for short queries that need more context.
96
+ """
97
+ expansions = []
98
+ normalized = normalize_query(query)
99
+ expansions.append(normalized)
100
+
101
+ # 1. Abbreviation expansion
102
+ abbrev_expansions = expand_abbreviations(normalized)
103
+ expansions.extend(abbrev_expansions)
104
+
105
+ # 2. Synonym expansion for each word
106
+ words = normalized.split()
107
+ for i, word in enumerate(words):
108
+ synonyms = get_synonyms(word)
109
+ for syn in list(synonyms)[:3]: # Top 3 synonyms
110
+ new_query = ' '.join(words[:i] + [syn] + words[i+1:])
111
+ expansions.append(new_query)
112
+
113
+ # 3. Multi-word phrase synonyms
114
+ from .medical_terminology import MEDICAL_SYNONYMS
115
+ for term, syn_list in MEDICAL_SYNONYMS.items():
116
+ if term in normalized:
117
+ for syn in syn_list[:3]:
118
+ expansions.append(normalized.replace(term, syn))
119
+
120
+ # 4. Spelling variations
121
+ from .medical_terminology import SPELLING_VARIATIONS
122
+ for us_spelling, uk_variants in SPELLING_VARIATIONS.items():
123
+ if us_spelling in normalized:
124
+ for uk_spelling in uk_variants:
125
+ expansions.append(normalized.replace(us_spelling, uk_spelling))
126
+
127
+ # Remove duplicates
128
+ return list(dict.fromkeys(expansions))[:10]
129
+
130
+ def _conservative_expansion(self, query: str) -> List[str]:
131
+ """
132
+ Conservative expansion with fewer variations.
133
+ Useful for specific, well-formed queries.
134
+ """
135
+ expansions = []
136
+ normalized = normalize_query(query)
137
+ expansions.append(normalized)
138
+
139
+ # Only expand obvious abbreviations
140
+ words = normalized.split()
141
+ for word in words:
142
+ if is_medical_abbreviation(word):
143
+ abbrev_expansions = expand_abbreviations(word)
144
+ for exp in abbrev_expansions[:2]: # Limit to 2
145
+ new_query = normalized.replace(word, exp)
146
+ expansions.append(new_query)
147
+
148
+ # Remove duplicates
149
+ return list(dict.fromkeys(expansions))[:5]
150
+
151
+ def _abbreviation_focused_expansion(self, query: str) -> List[str]:
152
+ """
153
+ Expansion focused on abbreviation handling.
154
+ Expands all abbreviations to their full forms.
155
+ """
156
+ expansions = []
157
+ normalized = normalize_query(query)
158
+ expansions.append(normalized)
159
+
160
+ # Identify and expand all abbreviations
161
+ words = normalized.split()
162
+ current_query = normalized
163
+
164
+ for word in words:
165
+ if is_medical_abbreviation(word):
166
+ full_forms = get_abbreviation_expansion(word)
167
+ for full_form in full_forms:
168
+ expanded = current_query.replace(word, full_form)
169
+ expansions.append(expanded)
170
+ # Also try with the expanded form as base for further expansion
171
+ current_query = expanded
172
+
173
+ # Remove duplicates
174
+ return list(dict.fromkeys(expansions))[:8]
175
+
176
+
177
+ class MultiQueryRetriever:
178
+ """
179
+ Retrieves documents using multiple query variations and merges results.
180
+ """
181
+
182
+ def __init__(self, base_retriever_func):
183
+ """
184
+ Args:
185
+ base_retriever_func: Function that takes (query, **kwargs) and returns List[Document]
186
+ """
187
+ self.base_retriever = base_retriever_func
188
+ self.query_expander = QueryExpansionStrategy()
189
+
190
+ def retrieve(
191
+ self,
192
+ query: str,
193
+ expansion_strategy: str = "adaptive",
194
+ merge_strategy: str = "weighted",
195
+ **retriever_kwargs
196
+ ) -> List[Document]:
197
+ """
198
+ Retrieve documents using multiple query variations.
199
+
200
+ Args:
201
+ query: Original query
202
+ expansion_strategy: How to expand the query
203
+ merge_strategy: How to merge results - "weighted", "union", "intersection"
204
+ **retriever_kwargs: Additional arguments for base retriever
205
+
206
+ Returns:
207
+ Merged list of documents
208
+ """
209
+ # Expand query
210
+ query_variations = self.query_expander.expand(query, strategy=expansion_strategy)
211
+
212
+ logger.info(f"Expanded query into {len(query_variations)} variations")
213
+ logger.debug(f"Query variations: {query_variations}")
214
+
215
+ # Retrieve for each variation
216
+ all_results = []
217
+ for i, var_query in enumerate(query_variations):
218
+ try:
219
+ docs = self.base_retriever(var_query, **retriever_kwargs)
220
+ # Tag documents with query variation rank
221
+ for doc in docs:
222
+ if not hasattr(doc, 'metadata'):
223
+ doc.metadata = {}
224
+ doc.metadata['query_variation_rank'] = i
225
+ doc.metadata['query_variation'] = var_query
226
+ all_results.append((var_query, docs))
227
+ except Exception as e:
228
+ logger.warning(f"Retrieval failed for variation '{var_query}': {e}")
229
+
230
+ # Merge results
231
+ if merge_strategy == "weighted":
232
+ merged = self._weighted_merge(all_results)
233
+ elif merge_strategy == "union":
234
+ merged = self._union_merge(all_results)
235
+ elif merge_strategy == "intersection":
236
+ merged = self._intersection_merge(all_results)
237
+ else:
238
+ # Default to weighted
239
+ merged = self._weighted_merge(all_results)
240
+
241
+ logger.info(f"Retrieved {len(merged)} unique documents after merging")
242
+ return merged
243
+
244
+ def _weighted_merge(self, results: List[Tuple[str, List[Document]]]) -> List[Document]:
245
+ """
246
+ Merge results with weighted scoring.
247
+ Earlier query variations get higher weight.
248
+ """
249
+ doc_scores = {} # doc_id -> (doc, score)
250
+
251
+ for query_idx, (query_var, docs) in enumerate(results):
252
+ # Weight decreases with query variation rank
253
+ query_weight = 1.0 / (query_idx + 1)
254
+
255
+ for doc_idx, doc in enumerate(docs):
256
+ # Create unique doc identifier
257
+ doc_id = self._get_doc_id(doc)
258
+
259
+ # Position score (earlier is better)
260
+ position_score = 1.0 / (doc_idx + 1)
261
+
262
+ # Combined score
263
+ score = query_weight * position_score
264
+
265
+ if doc_id in doc_scores:
266
+ # Document appeared in multiple variations - boost score
267
+ existing_doc, existing_score = doc_scores[doc_id]
268
+ doc_scores[doc_id] = (existing_doc, existing_score + score)
269
+ else:
270
+ doc_scores[doc_id] = (doc, score)
271
+
272
+ # Sort by score and return documents
273
+ sorted_docs = sorted(doc_scores.values(), key=lambda x: x[1], reverse=True)
274
+ return [doc for doc, score in sorted_docs]
275
+
276
+ def _union_merge(self, results: List[Tuple[str, List[Document]]]) -> List[Document]:
277
+ """
278
+ Merge results using union (all unique documents).
279
+ Preserves order from first appearance.
280
+ """
281
+ seen_ids = set()
282
+ merged = []
283
+
284
+ for query_var, docs in results:
285
+ for doc in docs:
286
+ doc_id = self._get_doc_id(doc)
287
+ if doc_id not in seen_ids:
288
+ seen_ids.add(doc_id)
289
+ merged.append(doc)
290
+
291
+ return merged
292
+
293
+ def _intersection_merge(self, results: List[Tuple[str, List[Document]]]) -> List[Document]:
294
+ """
295
+ Merge results using intersection (only documents in all variations).
296
+ Useful for high-precision retrieval.
297
+ """
298
+ if not results:
299
+ return []
300
+
301
+ # Get doc IDs from first variation
302
+ first_docs = {self._get_doc_id(doc): doc for doc in results[0][1]}
303
+ common_ids = set(first_docs.keys())
304
+
305
+ # Intersect with other variations
306
+ for query_var, docs in results[1:]:
307
+ current_ids = {self._get_doc_id(doc) for doc in docs}
308
+ common_ids &= current_ids
309
+
310
+ # Return documents that appear in all variations
311
+ return [first_docs[doc_id] for doc_id in common_ids if doc_id in first_docs]
312
+
313
+ def _get_doc_id(self, doc: Document) -> str:
314
+ """
315
+ Generate unique identifier for a document.
316
+ Uses source, page number, and content hash.
317
+ """
318
+ source = doc.metadata.get('source', 'unknown')
319
+ page = doc.metadata.get('page_number', 'unknown')
320
+ content_hash = hash(doc.page_content[:200]) # Hash first 200 chars
321
+ return f"{source}_{page}_{content_hash}"
322
+
323
+
324
+ class SemanticQueryExpander:
325
+ """
326
+ Expands queries using semantic understanding.
327
+ Uses context and co-occurrence patterns.
328
+ """
329
+
330
+ def __init__(self):
331
+ from .medical_terminology import get_terminology_learner
332
+ self.learner = get_terminology_learner()
333
+
334
+ def expand_with_context(self, query: str, context: Optional[str] = None) -> List[str]:
335
+ """
336
+ Expand query using contextual information.
337
+
338
+ Args:
339
+ query: Original query
340
+ context: Additional context (e.g., previous queries, conversation history)
341
+
342
+ Returns:
343
+ List of contextually expanded queries
344
+ """
345
+ expansions = [query]
346
+ normalized = normalize_query(query)
347
+
348
+ # Extract key terms
349
+ entities = extract_medical_entities(normalized)
350
+
351
+ # Get related terms from learned patterns
352
+ for entity, entity_type in entities:
353
+ related = self.learner.get_related_terms(entity)
354
+ for related_term in list(related)[:3]:
355
+ expanded = normalized.replace(entity, related_term)
356
+ expansions.append(expanded)
357
+
358
+ # If context provided, extract relevant terms
359
+ if context:
360
+ context_entities = extract_medical_entities(normalize_query(context))
361
+ # Add context terms to query
362
+ for entity, _ in context_entities[:2]:
363
+ expansions.append(f"{normalized} {entity}")
364
+
365
+ return list(dict.fromkeys(expansions))[:7]
366
+
367
+ def expand_with_specialization(self, query: str, specialty: Optional[str] = None) -> List[str]:
368
+ """
369
+ Expand query with specialty-specific terminology.
370
+
371
+ Args:
372
+ query: Original query
373
+ specialty: Medical specialty (e.g., "oncology", "radiology")
374
+
375
+ Returns:
376
+ List of specialty-aware expanded queries
377
+ """
378
+ expansions = [query]
379
+
380
+ # Specialty-specific term mappings
381
+ specialty_terms = {
382
+ "oncology": ["cancer", "tumor", "malignancy", "neoplasm", "carcinoma"],
383
+ "radiology": ["imaging", "scan", "ct", "mri", "pet"],
384
+ "pathology": ["biopsy", "histology", "cytology", "tissue"],
385
+ "surgery": ["resection", "operative", "surgical", "procedure"],
386
+ }
387
+
388
+ if specialty and specialty.lower() in specialty_terms:
389
+ # Add specialty context to query
390
+ for term in specialty_terms[specialty.lower()][:2]:
391
+ if term not in query.lower():
392
+ expansions.append(f"{query} {term}")
393
+
394
+ return expansions
395
+
396
+
397
+ # ============================================================================
398
+ # CONVENIENCE FUNCTIONS
399
+ # ============================================================================
400
+
401
+ def expand_medical_query(
402
+ query: str,
403
+ strategy: str = "adaptive",
404
+ max_variations: int = 5
405
+ ) -> List[str]:
406
+ """
407
+ Convenience function to expand a medical query.
408
+
409
+ Args:
410
+ query: Original query
411
+ strategy: Expansion strategy
412
+ max_variations: Maximum number of variations
413
+
414
+ Returns:
415
+ List of query variations
416
+ """
417
+ expander = QueryExpansionStrategy()
418
+ variations = expander.expand(query, strategy=strategy)
419
+ return variations[:max_variations]
420
+
421
+
422
+ def create_multi_query_retriever(base_retriever_func):
423
+ """
424
+ Create a multi-query retriever instance.
425
+
426
+ Args:
427
+ base_retriever_func: Base retrieval function
428
+
429
+ Returns:
430
+ MultiQueryRetriever instance
431
+ """
432
+ return MultiQueryRetriever(base_retriever_func)
core/retrievers.py CHANGED
@@ -1,10 +1,17 @@
1
  from concurrent.futures import ThreadPoolExecutor
 
2
 
3
  from . import utils
4
  from langchain_community.retrievers import BM25Retriever
5
  from langchain.retrievers import EnsembleRetriever
 
6
  from .config import logger
7
  from .tracing import traceable
 
 
 
 
 
8
 
9
  # Global variables for lazy loading
10
  _vector_store = None
@@ -98,6 +105,14 @@ def is_initialized() -> bool:
98
  _retrieval_pool = ThreadPoolExecutor(max_workers=4)
99
 
100
 
 
 
 
 
 
 
 
 
101
  def _match_provider(doc, provider: str) -> bool:
102
  if not provider:
103
  return True
@@ -106,16 +121,47 @@ def _match_provider(doc, provider: str) -> bool:
106
 
107
 
108
  @traceable(name="VectorRetriever")
109
- def vector_search(query: str, provider: str | None = None, k: int = 5):
110
- """Search FAISS vector store with optional provider metadata filter."""
111
  _ensure_initialized()
112
  if not _vector_store:
113
  return []
 
 
 
 
 
114
  try:
115
- if provider:
116
- docs = _vector_store.similarity_search(query, k=k, filter={"provider": provider})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
  else:
118
- docs = _vector_store.similarity_search(query, k=k)
 
 
 
 
 
119
  # Ensure provider post-filter in case backend filter is lenient
120
  if provider:
121
  docs = [d for d in docs if _match_provider(d, provider)]
@@ -126,36 +172,75 @@ def vector_search(query: str, provider: str | None = None, k: int = 5):
126
 
127
 
128
  @traceable(name="BM25Retriever")
129
- def bm25_search(query: str, provider: str | None = None, k: int = 5):
130
- """Search BM25 using the global retriever and optionally filter by provider."""
131
  _ensure_initialized()
 
 
 
 
 
132
  try:
133
  if not _bm25_retriever:
134
  return []
135
- _bm25_retriever.k = max(1, k)
136
- docs = _bm25_retriever.get_relevant_documents(query) or []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  if provider:
138
  docs = [d for d in docs if _match_provider(d, provider)]
139
- return docs[:k]
140
  except Exception as e:
141
  logger.error(f"BM25 search failed: {e}")
142
  return []
143
 
144
 
145
- def hybrid_search(query: str, provider: str | None = None, k_vector: int = 5, k_bm25: int = 5):
146
- """Combine vector and BM25 results (provider-filtered if provided)."""
147
  _ensure_initialized() # Ensure retrievers are initialized before parallel execution
148
- f_vector = _retrieval_pool.submit(vector_search, query, provider, k_vector)
149
- f_bm25 = _retrieval_pool.submit(bm25_search, query, provider, k_bm25)
 
 
 
 
 
 
 
150
 
151
  v_docs = f_vector.result()
152
  b_docs = f_bm25.result()
153
- # Merge uniquely by (source, page_number, snippet)
154
  seen = set()
155
  merged = []
156
  for d in v_docs + b_docs:
157
- key = (d.metadata.get("source"), d.metadata.get("page_number"), d.page_content[:100])
158
- if key not in seen:
159
- seen.add(key)
160
  merged.append(d)
 
 
161
  return merged
 
1
  from concurrent.futures import ThreadPoolExecutor
2
+ from typing import List, Optional
3
 
4
  from . import utils
5
  from langchain_community.retrievers import BM25Retriever
6
  from langchain.retrievers import EnsembleRetriever
7
+ from langchain.schema import Document
8
  from .config import logger
9
  from .tracing import traceable
10
+ from .query_expansion import expand_medical_query, MultiQueryRetriever
11
+
12
+ # Global configuration for retrieval parameters
13
+ DEFAULT_K_VECTOR = 3 # Number of documents to retrieve from vector search
14
+ DEFAULT_K_BM25 = 2 # Number of documents to retrieve from BM25 search
15
 
16
  # Global variables for lazy loading
17
  _vector_store = None
 
105
  _retrieval_pool = ThreadPoolExecutor(max_workers=4)
106
 
107
 
108
+ def _get_doc_id(doc: Document) -> str:
109
+ """Generate unique identifier for a document."""
110
+ source = doc.metadata.get('source', 'unknown')
111
+ page = doc.metadata.get('page_number', 'unknown')
112
+ content_hash = hash(doc.page_content[:200]) # Hash first 200 chars
113
+ return f"{source}_{page}_{content_hash}"
114
+
115
+
116
  def _match_provider(doc, provider: str) -> bool:
117
  if not provider:
118
  return True
 
121
 
122
 
123
  @traceable(name="VectorRetriever")
124
+ def vector_search(query: str, provider: str | None = None, k: int = None, use_query_expansion: bool = True):
125
+ """Search FAISS vector store with optional provider metadata filter and query expansion."""
126
  _ensure_initialized()
127
  if not _vector_store:
128
  return []
129
+
130
+ # Use global default if k is not specified
131
+ if k is None:
132
+ k = DEFAULT_K_VECTOR
133
+
134
  try:
135
+ # Use query expansion for better medical term matching
136
+ if use_query_expansion:
137
+ query_variations = expand_medical_query(query, strategy="adaptive", max_variations=3)
138
+ logger.debug(f"Expanded query '{query}' into {len(query_variations)} variations")
139
+
140
+ # Retrieve with each variation and merge
141
+ all_docs = []
142
+ seen_ids = set()
143
+
144
+ for var_query in query_variations:
145
+ if provider:
146
+ docs = _vector_store.similarity_search(var_query, k=k, filter={"provider": provider})
147
+ else:
148
+ docs = _vector_store.similarity_search(var_query, k=k)
149
+
150
+ # Deduplicate while preserving order
151
+ for doc in docs:
152
+ doc_id = _get_doc_id(doc)
153
+ if doc_id not in seen_ids:
154
+ seen_ids.add(doc_id)
155
+ all_docs.append(doc)
156
+
157
+ docs = all_docs[:k * 2] # Return more results due to expansion
158
  else:
159
+ # Standard search without expansion
160
+ if provider:
161
+ docs = _vector_store.similarity_search(query, k=k, filter={"provider": provider})
162
+ else:
163
+ docs = _vector_store.similarity_search(query, k=k)
164
+
165
  # Ensure provider post-filter in case backend filter is lenient
166
  if provider:
167
  docs = [d for d in docs if _match_provider(d, provider)]
 
172
 
173
 
174
  @traceable(name="BM25Retriever")
175
+ def bm25_search(query: str, provider: str | None = None, k: int = None, use_query_expansion: bool = True):
176
+ """Search BM25 using the global retriever with query expansion and optional provider filter."""
177
  _ensure_initialized()
178
+
179
+ # Use global default if k is not specified
180
+ if k is None:
181
+ k = DEFAULT_K_BM25
182
+
183
  try:
184
  if not _bm25_retriever:
185
  return []
186
+
187
+ # Use query expansion for better medical term matching
188
+ if use_query_expansion:
189
+ query_variations = expand_medical_query(query, strategy="adaptive", max_variations=3)
190
+ logger.debug(f"BM25: Expanded query '{query}' into {len(query_variations)} variations")
191
+
192
+ # Retrieve with each variation and merge
193
+ all_docs = []
194
+ seen_ids = set()
195
+
196
+ for var_query in query_variations:
197
+ _bm25_retriever.k = max(1, k * 2)
198
+ docs = _bm25_retriever.get_relevant_documents(var_query) or []
199
+
200
+ # Deduplicate while preserving order
201
+ for doc in docs:
202
+ doc_id = _get_doc_id(doc)
203
+ if doc_id not in seen_ids:
204
+ seen_ids.add(doc_id)
205
+ all_docs.append(doc)
206
+
207
+ docs = all_docs[:k * 2] # Return more results due to expansion
208
+ else:
209
+ # Standard search without expansion
210
+ _bm25_retriever.k = max(1, k)
211
+ docs = _bm25_retriever.get_relevant_documents(query) or []
212
+
213
  if provider:
214
  docs = [d for d in docs if _match_provider(d, provider)]
215
+ return docs[:k * 2 if use_query_expansion else k]
216
  except Exception as e:
217
  logger.error(f"BM25 search failed: {e}")
218
  return []
219
 
220
 
221
+ def hybrid_search(query: str, provider: str | None = None, k_vector: int = None, k_bm25: int = None, use_query_expansion: bool = True):
222
+ """Combine vector and BM25 results with query expansion (provider-filtered if provided)."""
223
  _ensure_initialized() # Ensure retrievers are initialized before parallel execution
224
+
225
+ # Use global defaults if not specified
226
+ if k_vector is None:
227
+ k_vector = DEFAULT_K_VECTOR
228
+ if k_bm25 is None:
229
+ k_bm25 = DEFAULT_K_BM25
230
+
231
+ f_vector = _retrieval_pool.submit(vector_search, query, provider, k_vector, use_query_expansion)
232
+ f_bm25 = _retrieval_pool.submit(bm25_search, query, provider, k_bm25, use_query_expansion)
233
 
234
  v_docs = f_vector.result()
235
  b_docs = f_bm25.result()
236
+ # Merge uniquely by document ID
237
  seen = set()
238
  merged = []
239
  for d in v_docs + b_docs:
240
+ doc_id = _get_doc_id(d)
241
+ if doc_id not in seen:
242
+ seen.add(doc_id)
243
  merged.append(d)
244
+
245
+ logger.info(f"Hybrid search returned {len(merged)} unique documents (query expansion: {use_query_expansion})")
246
  return merged
core/tools.py CHANGED
@@ -11,6 +11,8 @@ from langchain.tools import tool
11
  from .retrievers import hybrid_search, vector_search, bm25_search
12
  from .validation import validate_medical_answer
13
  from .github_storage import get_github_storage
 
 
14
  from langchain_openai import ChatOpenAI
15
 
16
  CANONICAL_PROVIDERS = {"Manus", "ASCO", "NCCN", "ESMO", "NICE"}
@@ -160,21 +162,31 @@ def _format_docs_with_citations(docs: List[Document]) -> str:
160
  page = meta.get("page_number", "?")
161
  provider = meta.get("provider", "unknown")
162
  disease = meta.get("disease", "unknown")
 
 
163
  snippet = clear_text(d.page_content)
164
- parts.append(
165
- f"Result {i}:\n"
166
- f"Provider: {provider} | Disease: {disease} | Source: {source} | Page: {page}\n"
167
- f"Text:\n{snippet}\n"
168
- )
 
 
 
 
 
 
 
169
  return "\n\n".join(parts) if parts else "No results."
170
 
171
 
172
  @tool
173
  def medical_guidelines_knowledge_tool(query: str, provider: Optional[str] = None) -> str:
174
  """
175
- Retrieve medical guideline knowledge for a query with optional provider filtering.
 
176
  If provider is provided (e.g., "NCCN", "ASCO", "ESMO", "NICE"), results will be filtered by metadata provider.
177
- Always returns text with full metadata (source file, page number, provider, disease) for each result.
178
  """
179
  global _last_question, _last_documents
180
  try:
@@ -183,25 +195,46 @@ def medical_guidelines_knowledge_tool(query: str, provider: Optional[str] = None
183
 
184
  # Normalize provider name from either explicit arg or query text
185
  normalized_provider = _normalize_provider(provider, query)
186
- # Use hybrid search by default for quality
187
- docs = hybrid_search(query=query, provider=normalized_provider, k_vector=5, k_bm25=5)
188
 
189
- # Store documents for validation context
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
190
  _last_documents = []
191
- for doc in docs:
192
  doc_dict = {
193
- "doc_id": getattr(doc, 'id', f"doc_{len(_last_documents)}"),
194
  "source": doc.metadata.get("source", "unknown"),
195
  "provider": doc.metadata.get("provider", "unknown"),
196
  "page_number": doc.metadata.get("page_number", "unknown"),
197
  "disease": doc.metadata.get("disease", "unknown"),
198
- "snippet": doc.page_content[:500] + "..." if len(doc.page_content) > 500 else doc.page_content,
 
 
 
 
 
199
  "content": doc.page_content
200
  }
201
  _last_documents.append(doc_dict)
202
 
203
- return _format_docs_with_citations(docs)
204
  except Exception as e:
 
205
  return f"Retrieval error: {str(e)}"
206
 
207
 
 
11
  from .retrievers import hybrid_search, vector_search, bm25_search
12
  from .validation import validate_medical_answer
13
  from .github_storage import get_github_storage
14
+ from .context_enrichment import enrich_retrieved_documents
15
+ from .config import logger
16
  from langchain_openai import ChatOpenAI
17
 
18
  CANONICAL_PROVIDERS = {"Manus", "ASCO", "NCCN", "ESMO", "NICE"}
 
162
  page = meta.get("page_number", "?")
163
  provider = meta.get("provider", "unknown")
164
  disease = meta.get("disease", "unknown")
165
+ is_context = meta.get("context_enrichment", False)
166
+
167
  snippet = clear_text(d.page_content)
168
+
169
+ # Build citation header
170
+ citation = f"Result {i}:\n"
171
+ citation += f"Provider: {provider} | Disease: {disease} | Source: {source} | Page: {page}"
172
+
173
+ # Add context enrichment marker if this is a context page
174
+ if is_context:
175
+ citation += " [CONTEXT PAGE]"
176
+
177
+ citation += f"\nText:\n{snippet}\n"
178
+ parts.append(citation)
179
+
180
  return "\n\n".join(parts) if parts else "No results."
181
 
182
 
183
  @tool
184
  def medical_guidelines_knowledge_tool(query: str, provider: Optional[str] = None) -> str:
185
  """
186
+ Retrieve comprehensive medical guideline knowledge with enriched context.
187
+ Includes surrounding pages (before/after) for top results to provide complete clinical context.
188
  If provider is provided (e.g., "NCCN", "ASCO", "ESMO", "NICE"), results will be filtered by metadata provider.
189
+ Returns detailed text with full metadata and contextual information for expert analysis.
190
  """
191
  global _last_question, _last_documents
192
  try:
 
195
 
196
  # Normalize provider name from either explicit arg or query text
197
  normalized_provider = _normalize_provider(provider, query)
 
 
198
 
199
+ # Use hybrid search with query expansion for comprehensive retrieval
200
+ # Uses global defaults: DEFAULT_K_VECTOR=7, DEFAULT_K_BM25=3 (configurable in core/retrievers.py)
201
+ docs = hybrid_search(query=query, provider=normalized_provider)
202
+
203
+ # Enrich top documents with surrounding pages for richer context
204
+ # This provides complete clinical context including adjacent information
205
+ enriched_docs = enrich_retrieved_documents(
206
+ documents=docs,
207
+ pages_before=1, # Include 1 page before
208
+ pages_after=1, # Include 1 page after
209
+ max_enriched=5 # Enrich top 5 most relevant documents
210
+ )
211
+
212
+ # Count context pages added
213
+ context_pages_count = sum(1 for doc in enriched_docs if doc.metadata.get("context_enrichment", False))
214
+ logger.info(f"Retrieved {len(docs)} documents, added {context_pages_count} context pages")
215
+
216
+ # Store documents for validation context with enrichment metadata
217
  _last_documents = []
218
+ for doc in enriched_docs:
219
  doc_dict = {
220
+ "doc_id": getattr(doc, 'id', None),
221
  "source": doc.metadata.get("source", "unknown"),
222
  "provider": doc.metadata.get("provider", "unknown"),
223
  "page_number": doc.metadata.get("page_number", "unknown"),
224
  "disease": doc.metadata.get("disease", "unknown"),
225
+ "context_enrichment": doc.metadata.get("context_enrichment", False),
226
+ "enriched": doc.metadata.get("enriched", False),
227
+ "pages_included": doc.metadata.get("pages_included", []),
228
+ "primary_page": doc.metadata.get("primary_page"),
229
+ "context_pages_before": doc.metadata.get("context_pages_before"),
230
+ "context_pages_after": doc.metadata.get("context_pages_after"),
231
  "content": doc.page_content
232
  }
233
  _last_documents.append(doc_dict)
234
 
235
+ return _format_docs_with_citations(enriched_docs)
236
  except Exception as e:
237
+ logger.error(f"Retrieval error: {str(e)}")
238
  return f"Retrieval error: {str(e)}"
239
 
240
 
core/validation.py CHANGED
@@ -25,7 +25,7 @@ class MedicalAnswerValidator:
25
  logger.info("Medical answer validator initialized successfully")
26
 
27
  def _get_next_interaction_id(self) -> str:
28
- """Get a temporary interaction ID (will be replaced by GitHub storage with unique ID)."""
29
  try:
30
  # Try to get from GitHub first
31
  github_storage = get_github_storage()
@@ -35,6 +35,7 @@ class MedicalAnswerValidator:
35
  try:
36
  evaluations = json.loads(existing_content)
37
  if evaluations and isinstance(evaluations, list):
 
38
  # Find the highest existing ID
39
  max_id = 0
40
  for eval_item in evaluations:
@@ -43,16 +44,21 @@ class MedicalAnswerValidator:
43
  max_id = max(max_id, current_id)
44
  except (ValueError, TypeError):
45
  continue
46
- return str(max_id + 1)
47
- except json.JSONDecodeError:
 
 
 
48
  pass
49
 
50
  # Fallback to local file check
51
  if os.path.exists(self.evaluation_file):
 
52
  with open(self.evaluation_file, "r", encoding="utf-8") as f:
53
  evaluations = json.load(f)
54
 
55
  if evaluations:
 
56
  # Find the highest existing ID
57
  max_id = 0
58
  for eval_item in evaluations:
@@ -61,10 +67,14 @@ class MedicalAnswerValidator:
61
  max_id = max(max_id, current_id)
62
  except (ValueError, TypeError):
63
  continue
64
- return str(max_id + 1)
 
 
65
  else:
 
66
  return "1"
67
  else:
 
68
  return "1"
69
  except Exception as e:
70
  logger.error(f"Error getting next interaction ID: {e}")
@@ -74,12 +84,16 @@ class MedicalAnswerValidator:
74
  """Clean documents by removing snippets and keeping only essential fields."""
75
  cleaned_docs = []
76
  for doc in documents:
 
 
77
  cleaned_doc = {
78
  "doc_id": doc.get("doc_id"),
79
  "source": doc.get("source", "unknown"),
80
  "provider": doc.get("provider", "unknown"),
81
  "page_number": doc.get("page_number", "unknown"),
82
  "disease": doc.get("disease", "unknown"),
 
 
83
  "content": doc.get("content", "")
84
  }
85
  cleaned_docs.append(cleaned_doc)
 
25
  logger.info("Medical answer validator initialized successfully")
26
 
27
  def _get_next_interaction_id(self) -> str:
28
+ """Get the next interaction ID by finding the highest existing ID and adding 1."""
29
  try:
30
  # Try to get from GitHub first
31
  github_storage = get_github_storage()
 
35
  try:
36
  evaluations = json.loads(existing_content)
37
  if evaluations and isinstance(evaluations, list):
38
+ logger.info(f"Found {len(evaluations)} existing evaluations in GitHub")
39
  # Find the highest existing ID
40
  max_id = 0
41
  for eval_item in evaluations:
 
44
  max_id = max(max_id, current_id)
45
  except (ValueError, TypeError):
46
  continue
47
+ next_id = str(max_id + 1)
48
+ logger.info(f"Next interaction ID will be: {next_id}")
49
+ return next_id
50
+ except json.JSONDecodeError as e:
51
+ logger.warning(f"Failed to parse GitHub evaluation file: {e}")
52
  pass
53
 
54
  # Fallback to local file check
55
  if os.path.exists(self.evaluation_file):
56
+ logger.info("GitHub file not found, checking local file")
57
  with open(self.evaluation_file, "r", encoding="utf-8") as f:
58
  evaluations = json.load(f)
59
 
60
  if evaluations:
61
+ logger.info(f"Found {len(evaluations)} existing evaluations in local file")
62
  # Find the highest existing ID
63
  max_id = 0
64
  for eval_item in evaluations:
 
67
  max_id = max(max_id, current_id)
68
  except (ValueError, TypeError):
69
  continue
70
+ next_id = str(max_id + 1)
71
+ logger.info(f"Next interaction ID from local file: {next_id}")
72
+ return next_id
73
  else:
74
+ logger.info("Local file is empty, starting with ID 1")
75
  return "1"
76
  else:
77
+ logger.info("No existing evaluation file found, starting with ID 1")
78
  return "1"
79
  except Exception as e:
80
  logger.error(f"Error getting next interaction ID: {e}")
 
84
  """Clean documents by removing snippets and keeping only essential fields."""
85
  cleaned_docs = []
86
  for doc in documents:
87
+ is_context_page = doc.get("context_enrichment", False)
88
+
89
  cleaned_doc = {
90
  "doc_id": doc.get("doc_id"),
91
  "source": doc.get("source", "unknown"),
92
  "provider": doc.get("provider", "unknown"),
93
  "page_number": doc.get("page_number", "unknown"),
94
  "disease": doc.get("disease", "unknown"),
95
+ "page_type": "CONTEXT PAGE" if is_context_page else "ORIGINAL PAGE",
96
+ "context_enrichment": is_context_page,
97
  "content": doc.get("content", "")
98
  }
99
  cleaned_docs.append(cleaned_doc)
data/medical_terms_cache.json ADDED
@@ -0,0 +1,3420 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "synonyms": {
3
+ "european society of medical oncology": [
4
+ "esmo"
5
+ ],
6
+ "esmo": [
7
+ "european society of medical oncology",
8
+ "european society for medical oncology",
9
+ "european\nsociety of medical oncology",
10
+ "european society for\nmedical oncology",
11
+ "the european society for medical oncology",
12
+ "the european society for medical\noncology"
13
+ ],
14
+ "american society of clinical\n\noncology": [
15
+ "asco"
16
+ ],
17
+ "asco": [
18
+ "md american society of clinical oncology",
19
+ "american\nsociety of clinical oncology",
20
+ "american society of clinical\n\noncology",
21
+ "american society of clinical oncology",
22
+ "inc"
23
+ ],
24
+ "italian association of medical oncology": [
25
+ "aiom"
26
+ ],
27
+ "aiom": [
28
+ "italian association\nof medical oncology",
29
+ "italian association of medical oncology"
30
+ ],
31
+ "national comprehensive cancer network": [
32
+ "nccn"
33
+ ],
34
+ "nccn": [
35
+ "leading american cancer centers",
36
+ "national comprehensive cancer network",
37
+ "vs insurance-based"
38
+ ],
39
+ "non-small cell lung cancer": [
40
+ "nsclc"
41
+ ],
42
+ "nsclc": [
43
+ "mutant advanced non-small cell lung cancer",
44
+ "small cell\nlung cancer",
45
+ "non-small-cell lung cancer",
46
+ "non-small cell lung cancer",
47
+ "lung cancer",
48
+ "stage iii non small cell lung cancer",
49
+ "robotic lobectomy for non-small cell lung cancer",
50
+ "cancer",
51
+ "advanced non-small-cell lung cancer",
52
+ "small-cell lung cancer",
53
+ "iii non-small-cell lung cancer",
54
+ "advanced non-small cell lung cancer",
55
+ "small-cell\nlung cancer"
56
+ ],
57
+ "american\nsociety of clinical oncology": [
58
+ "asco"
59
+ ],
60
+ "italian association\nof medical oncology": [
61
+ "aiom"
62
+ ],
63
+ "european\nsociety of medical oncology": [
64
+ "esmo"
65
+ ],
66
+ "leading american cancer centers": [
67
+ "nccn"
68
+ ],
69
+ "using the guidelines into decision\nsupport": [
70
+ "glides"
71
+ ],
72
+ "glides": [
73
+ "using the guidelines into decision\nsupport",
74
+ "guidelines into decision support"
75
+ ],
76
+ "for all the newly\neuropean medicines agency": [
77
+ "ema"
78
+ ],
79
+ "ema": [
80
+ "european medicines agency",
81
+ "and the european medicines\nagency",
82
+ "for all the newly\neuropean medicines agency",
83
+ "not european medicines agency"
84
+ ],
85
+ "evaluates treatments with curative intent": [
86
+ "such\nas adjuvant chemotherapy"
87
+ ],
88
+ "such\nas adjuvant chemotherapy": [
89
+ "evaluates treatments with curative intent"
90
+ ],
91
+ "panel members": [
92
+ "from\ndifferent institutions"
93
+ ],
94
+ "from\ndifferent institutions": [
95
+ "panel members"
96
+ ],
97
+ "and the\nearly study interruption": [
98
+ "even if based on pre-specified\ninterim analysis"
99
+ ],
100
+ "even if based on pre-specified\ninterim analysis": [
101
+ "and the\nearly study interruption"
102
+ ],
103
+ "-positive nonsmall-cell lung cancer": [
104
+ "magrit"
105
+ ],
106
+ "magrit": [
107
+ "-positive nonsmall-cell lung cancer"
108
+ ],
109
+ "guidelines into decision support": [
110
+ "glides"
111
+ ],
112
+ "early-stage and\n\nlocally advanced": [
113
+ "non-metastatic"
114
+ ],
115
+ "non-metastatic": [
116
+ "early-stage and\n\nlocally advanced"
117
+ ],
118
+ "or best supportive\ncare": [
119
+ "bsc"
120
+ ],
121
+ "bsc": [
122
+ "leads to\nincreased dfs versus best supportive care",
123
+ "or best supportive\ncare"
124
+ ],
125
+ "author affiliations\nand support\n\ninformation": [
126
+ "if\n\napplicable"
127
+ ],
128
+ "if\n\napplicable": [
129
+ "author affiliations\nand support\n\ninformation"
130
+ ],
131
+ "small-cell lung cancers": [
132
+ "nsclcs"
133
+ ],
134
+ "nsclcs": [
135
+ "small-cell lung cancers"
136
+ ],
137
+ "two randomized control trials": [
138
+ "rcts"
139
+ ],
140
+ "rcts": [
141
+ "controlled trials",
142
+ "two randomized control trials",
143
+ "clinical trials"
144
+ ],
145
+ "the primary end point was disease-free\nsurvival": [
146
+ "dfs"
147
+ ],
148
+ "dfs": [
149
+ "the primary end point was disease-free\nsurvival"
150
+ ],
151
+ "joint cancer care ontario": [
152
+ "cco"
153
+ ],
154
+ "cco": [
155
+ "joint cancer care ontario"
156
+ ],
157
+ "small-cell\nlung cancer": [
158
+ "nsclc"
159
+ ],
160
+ "puma biotechnology": [
161
+ "inst"
162
+ ],
163
+ "inst": [
164
+ "calithera biosciences",
165
+ "novartis",
166
+ "cullinan oncology",
167
+ "regeneron",
168
+ "glaxosmithkline canada",
169
+ "oncomed",
170
+ "genentech",
171
+ "verastem",
172
+ "bayer",
173
+ "bristol myers squibb foundation",
174
+ "puma biotechnology",
175
+ "boehringer ingelheim",
176
+ "amgen",
177
+ "arcus biosciences",
178
+ "turning point therapeutics",
179
+ "crispr\ntherapeutics",
180
+ "msd",
181
+ "takeda",
182
+ "revolution medicines",
183
+ "merck serono",
184
+ "macrogenics",
185
+ "oric pharmaceuticals",
186
+ "astrazeneca",
187
+ "merck",
188
+ "summit therapeutics",
189
+ "palobiofarma",
190
+ "astex pharmaceuticals",
191
+ "black diamond\ntherapeutics",
192
+ "janssen oncology",
193
+ "mirati therapeutics",
194
+ "bristol myers squibb",
195
+ "abbvie",
196
+ "dohme",
197
+ "anheart therapeutics",
198
+ "neogenomics",
199
+ "sutro biopharma",
200
+ "polaris",
201
+ "pfizer",
202
+ "forward",
203
+ "elevation oncology",
204
+ "astra zeneca",
205
+ "nuvation bio",
206
+ "bms",
207
+ "gsk",
208
+ "inhibrx",
209
+ "bristol myers\nsquibb",
210
+ "roche",
211
+ "bristol-myers squibb",
212
+ "dizal\npharma",
213
+ "harpoon therapeutics",
214
+ "vivace therapeutics",
215
+ "janssen",
216
+ "jazz pharmaceuticals",
217
+ "lilly",
218
+ "advaxis",
219
+ "astrazeneca canada",
220
+ "constellation pharmaceuticals",
221
+ "guardant health",
222
+ "trizell",
223
+ "pharmamar",
224
+ "medimmune",
225
+ "inc",
226
+ "blueprint medicines",
227
+ "glaxosmithkline",
228
+ "therapeutics",
229
+ "exelixis"
230
+ ],
231
+ "pfizer": [
232
+ "inst"
233
+ ],
234
+ "genentech": [
235
+ "inst"
236
+ ],
237
+ "bristol-myers squibb": [
238
+ "inst"
239
+ ],
240
+ "medimmune": [
241
+ "inst"
242
+ ],
243
+ "of patients with\nstage i to iii sclc": [
244
+ "limited stage"
245
+ ],
246
+ "limited stage": [
247
+ "of patients with\nstage i to iii sclc"
248
+ ],
249
+ "small-cell lung cancer": [
250
+ "pacific",
251
+ "nsclc"
252
+ ],
253
+ "or small-cell lung cancer": [
254
+ "sclc"
255
+ ],
256
+ "sclc": [
257
+ "small cell lung cancer",
258
+ "trial in small cell lung cancer",
259
+ "and small-cell lung cancer",
260
+ "or small-cell lung cancer"
261
+ ],
262
+ "cancer": [
263
+ "relay",
264
+ "nsclc"
265
+ ],
266
+ "and small-cell lung cancer": [
267
+ "sclc"
268
+ ],
269
+ "with contrast": [
270
+ "preferred"
271
+ ],
272
+ "preferred": [
273
+ "with contrast"
274
+ ],
275
+ "prophylactic cranial irradiation": [
276
+ "pci"
277
+ ],
278
+ "pci": [
279
+ "dose prophylactic cranial irradiation",
280
+ "prophylactic cranial irradiation"
281
+ ],
282
+ "the bottom line": [
283
+ "continued"
284
+ ],
285
+ "continued": [
286
+ "the bottom line",
287
+ "all recommendations"
288
+ ],
289
+ "salvage stereotactic body radiation therapy": [
290
+ "sbrt"
291
+ ],
292
+ "sbrt": [
293
+ "salvage stereotactic body radiation therapy",
294
+ "sabr or stereotactic body radiotherapy",
295
+ "fdg-pet and stereotactic body radiotherapy",
296
+ "stereotactic body radiotherapy"
297
+ ],
298
+ "oncomed": [
299
+ "inst"
300
+ ],
301
+ "macrogenics": [
302
+ "inst"
303
+ ],
304
+ "astrazeneca": [
305
+ "inst"
306
+ ],
307
+ "thecollege of americanpathologists": [
308
+ "cap"
309
+ ],
310
+ "cap": [
311
+ "thecollege of americanpathologists"
312
+ ],
313
+ "association\nfor molecular pathology": [
314
+ "amp"
315
+ ],
316
+ "amp": [
317
+ "association\nfor molecular pathology"
318
+ ],
319
+ "and anaplastic lymphoma kinase": [
320
+ "alk"
321
+ ],
322
+ "alk": [
323
+ "positive anaplastic lymphoma kinase",
324
+ "crizotinib-pretreated anaplastic lymphoma kinase",
325
+ "and anaplastic lymphoma kinase"
326
+ ],
327
+ "immunohistochemistry": [
328
+ "ihc"
329
+ ],
330
+ "ihc": [
331
+ "egfr fish or immunohistochemistry",
332
+ "immunohistochemistry"
333
+ ],
334
+ "merck": [
335
+ "german",
336
+ "inst"
337
+ ],
338
+ "glaxosmithkline": [
339
+ "inst",
340
+ "gsk"
341
+ ],
342
+ "astex pharmaceuticals": [
343
+ "inst"
344
+ ],
345
+ "takeda": [
346
+ "inst"
347
+ ],
348
+ "bristol myers\nsquibb": [
349
+ "inst",
350
+ "bms"
351
+ ],
352
+ "polaris": [
353
+ "inst"
354
+ ],
355
+ "inhibrx": [
356
+ "inst"
357
+ ],
358
+ "vivace therapeutics": [
359
+ "inst"
360
+ ],
361
+ "constellation pharmaceuticals": [
362
+ "inst"
363
+ ],
364
+ "harpoon therapeutics": [
365
+ "inst"
366
+ ],
367
+ "bayer": [
368
+ "inst"
369
+ ],
370
+ "novartis": [
371
+ "inst"
372
+ ],
373
+ "crispr\ntherapeutics": [
374
+ "inst"
375
+ ],
376
+ "calithera biosciences": [
377
+ "inst"
378
+ ],
379
+ "therapeutics": [
380
+ "inst"
381
+ ],
382
+ "stage iii non small cell lung cancer": [
383
+ "nsclc"
384
+ ],
385
+ "immune checkpoint inhibitors": [
386
+ "icis"
387
+ ],
388
+ "icis": [
389
+ "neoadjuvant immune checkpoint inhibitors",
390
+ "immune checkpoint inhibitors"
391
+ ],
392
+ "american society of clinical oncology": [
393
+ "asco"
394
+ ],
395
+ "boehringer ingelheim": [
396
+ "inst"
397
+ ],
398
+ "pharmamar": [
399
+ "inst"
400
+ ],
401
+ "roche": [
402
+ "inst"
403
+ ],
404
+ "janssen": [
405
+ "inst"
406
+ ],
407
+ "merck serono": [
408
+ "inst"
409
+ ],
410
+ "bms": [
411
+ "bristol\nmyers squibb",
412
+ "bristol-myers\nsquibb",
413
+ "bristol myers squibb",
414
+ "bristol myers\nsquibb",
415
+ "inst",
416
+ "celgene"
417
+ ],
418
+ "trizell": [
419
+ "inst"
420
+ ],
421
+ "amgen": [
422
+ "inst"
423
+ ],
424
+ "clinical lung cancer": [
425
+ "elsevier"
426
+ ],
427
+ "elsevier": [
428
+ "clinical lung cancer"
429
+ ],
430
+ "one randomized controlled trial": [
431
+ "rct"
432
+ ],
433
+ "rct": [
434
+ "phase iii randomised clinical trial",
435
+ "phase iib\nrandomised controlled trial",
436
+ "one randomized controlled trial",
437
+ "a phase iii randomised clinical trial"
438
+ ],
439
+ "the primary end point of progression-free survival": [
440
+ "pfs"
441
+ ],
442
+ "pfs": [
443
+ "quality of life and progression-free survival",
444
+ "the primary end point of progression-free survival",
445
+ "the median\nprogression-free survival",
446
+ "the median progression-free\nsurvival",
447
+ "no\nimprovement in progression-free survival",
448
+ "and\nprogression-free survival",
449
+ "reported improved\nprogression-free survival"
450
+ ],
451
+ "adverse events": [
452
+ "aes"
453
+ ],
454
+ "aes": [
455
+ "mainly altered lipid levels",
456
+ "adverse\nevents",
457
+ "adverse events"
458
+ ],
459
+ "and consolidation": [
460
+ "for unresectable stage iii nsclc"
461
+ ],
462
+ "for unresectable stage iii nsclc": [
463
+ "and consolidation"
464
+ ],
465
+ "treatment is now an\negfr-targeted drug": [
466
+ "osimertinib"
467
+ ],
468
+ "osimertinib": [
469
+ "treatment is now an\negfr-targeted drug"
470
+ ],
471
+ "inc": [
472
+ "asco",
473
+ "inst"
474
+ ],
475
+ "small cell\nlung cancer": [
476
+ "nsclc"
477
+ ],
478
+ "the median\nprogression-free survival": [
479
+ "pfs"
480
+ ],
481
+ "adverse\nevents": [
482
+ "aes"
483
+ ],
484
+ "and vascular\nendothelial growth factor": [
485
+ "vegf"
486
+ ],
487
+ "vegf": [
488
+ "and vascular\nendothelial growth factor"
489
+ ],
490
+ "though rates of\nimmune-related aes": [
491
+ "iraes"
492
+ ],
493
+ "iraes": [
494
+ "though rates of\nimmune-related aes"
495
+ ],
496
+ "bristol myers squibb": [
497
+ "inst",
498
+ "bms"
499
+ ],
500
+ "palobiofarma": [
501
+ "inst"
502
+ ],
503
+ "dohme": [
504
+ "msd",
505
+ "inst"
506
+ ],
507
+ "mirati therapeutics": [
508
+ "inst"
509
+ ],
510
+ "abbvie": [
511
+ "inst"
512
+ ],
513
+ "blueprint medicines": [
514
+ "inst"
515
+ ],
516
+ "advaxis": [
517
+ "inst"
518
+ ],
519
+ "janssen oncology": [
520
+ "inst"
521
+ ],
522
+ "elevation oncology": [
523
+ "inst"
524
+ ],
525
+ "black diamond\ntherapeutics": [
526
+ "inst"
527
+ ],
528
+ "forward": [
529
+ "inst"
530
+ ],
531
+ "gsk": [
532
+ "inst",
533
+ "glaxosmithkline"
534
+ ],
535
+ "regeneron": [
536
+ "inst"
537
+ ],
538
+ "jazz pharmaceuticals": [
539
+ "inst"
540
+ ],
541
+ "oric pharmaceuticals": [
542
+ "inst"
543
+ ],
544
+ "summit therapeutics": [
545
+ "inst"
546
+ ],
547
+ "turning point therapeutics": [
548
+ "inst"
549
+ ],
550
+ "anheart therapeutics": [
551
+ "inst"
552
+ ],
553
+ "nuvation bio": [
554
+ "inst"
555
+ ],
556
+ "and terminology": [
557
+ "data supplement"
558
+ ],
559
+ "data supplement": [
560
+ "and terminology"
561
+ ],
562
+ "nab-paclitaxel with or without bevacizumab": [
563
+ "in the absence of\ncontraindications to bevacizumab"
564
+ ],
565
+ "in the absence of\ncontraindications to bevacizumab": [
566
+ "nab-paclitaxel with or without bevacizumab"
567
+ ],
568
+ "paclitaxel": [
569
+ "or nab-paclitaxel"
570
+ ],
571
+ "or nab-paclitaxel": [
572
+ "paclitaxel"
573
+ ],
574
+ "all recommendations": [
575
+ "continued"
576
+ ],
577
+ "interdisciplinary palliative care teams": [
578
+ "consultation"
579
+ ],
580
+ "consultation": [
581
+ "interdisciplinary palliative care teams"
582
+ ],
583
+ "md american society of clinical oncology": [
584
+ "asco"
585
+ ],
586
+ "va asco practice guideline staff": [
587
+ "health research methods"
588
+ ],
589
+ "health research methods": [
590
+ "va asco practice guidelines staff",
591
+ "va asco practice guideline staff"
592
+ ],
593
+ "in tyrosine kinase inhibitor": [
594
+ "tki"
595
+ ],
596
+ "tki": [
597
+ "in tyrosine kinase inhibitor",
598
+ "tyrosine kinase inhibitor"
599
+ ],
600
+ "reuss et al\n\n\n\nrate": [
601
+ "orr"
602
+ ],
603
+ "orr": [
604
+ "reuss et al\n\n\n\nrate",
605
+ "which had an overall response rate"
606
+ ],
607
+ "disease control rate": [
608
+ "dcr"
609
+ ],
610
+ "dcr": [
611
+ "disease control rate"
612
+ ],
613
+ "limited generalizability": [
614
+ "united states only"
615
+ ],
616
+ "united states only": [
617
+ "limited generalizability"
618
+ ],
619
+ "with a median duration of\nresponse": [
620
+ "dor"
621
+ ],
622
+ "dor": [
623
+ "with a median duration of\nresponse",
624
+ "the median\nduration of response"
625
+ ],
626
+ "the most common treatment-emergent adverse events": [
627
+ "teaes"
628
+ ],
629
+ "teaes": [
630
+ "the most common treatment-emergent adverse events"
631
+ ],
632
+ "verastem": [
633
+ "inst"
634
+ ],
635
+ "exelixis": [
636
+ "inst"
637
+ ],
638
+ "arcus biosciences": [
639
+ "inst"
640
+ ],
641
+ "revolution medicines": [
642
+ "inst"
643
+ ],
644
+ "sutro biopharma": [
645
+ "inst"
646
+ ],
647
+ "dizal\npharma": [
648
+ "inst"
649
+ ],
650
+ "msd": [
651
+ "dohme",
652
+ "inst"
653
+ ],
654
+ "lilly": [
655
+ "inst"
656
+ ],
657
+ "astrazeneca canada": [
658
+ "inst"
659
+ ],
660
+ "neogenomics": [
661
+ "inst"
662
+ ],
663
+ "guardant health": [
664
+ "inst"
665
+ ],
666
+ "glaxosmithkline canada": [
667
+ "inst"
668
+ ],
669
+ "va asco practice guidelines staff": [
670
+ "health research methods"
671
+ ],
672
+ "was published by asco and ontario health": [
673
+ "cancer care ontario"
674
+ ],
675
+ "cancer care ontario": [
676
+ "was published by asco and ontario health",
677
+ "asco-ontario health"
678
+ ],
679
+ "the median progression-free\nsurvival": [
680
+ "pfs"
681
+ ],
682
+ "pneumonitis": [
683
+ "of any cause"
684
+ ],
685
+ "of any cause": [
686
+ "pneumonitis"
687
+ ],
688
+ "consolidation immunotherapy": [
689
+ "durvalumab"
690
+ ],
691
+ "durvalumab": [
692
+ "if ps improves\n\nv\n\nconsolidation immunotherapy",
693
+ "consolidation immunotherapy"
694
+ ],
695
+ "if ps improves\n\nv\n\nconsolidation immunotherapy": [
696
+ "durvalumab"
697
+ ],
698
+ "and sclc-i": [
699
+ "inflamed phenotype"
700
+ ],
701
+ "inflamed phenotype": [
702
+ "and sclc-i"
703
+ ],
704
+ "a bispecific t-cell\nengager": [
705
+ "bite"
706
+ ],
707
+ "bite": [
708
+ "a bispecific t-cell\nengager"
709
+ ],
710
+ "the most\ncommon ae was cytokine release syndrome": [
711
+ "crs"
712
+ ],
713
+ "crs": [
714
+ "the most\ncommon ae was cytokine release syndrome",
715
+ "cytokine release syndrome"
716
+ ],
717
+ "asco-ontario health": [
718
+ "cancer care ontario"
719
+ ],
720
+ "trial in small cell lung cancer": [
721
+ "sclc"
722
+ ],
723
+ "cullinan oncology": [
724
+ "inst"
725
+ ],
726
+ "astra zeneca": [
727
+ "inst"
728
+ ],
729
+ "bristol myers squibb foundation": [
730
+ "inst"
731
+ ],
732
+ "and\nprogression-free survival": [
733
+ "pfs"
734
+ ],
735
+ "the us food and drug administration": [
736
+ "fda"
737
+ ],
738
+ "fda": [
739
+ "and the united states food and drug administration",
740
+ "the food and drug administration",
741
+ "the us food and drug administration",
742
+ "food and drug administration",
743
+ "or food and drug administration",
744
+ "and the food and drug administration",
745
+ "entrectinib received food and\ndrug administration"
746
+ ],
747
+ "cytokine release syndrome": [
748
+ "crs"
749
+ ],
750
+ "associated neurotoxicity\nsyndrome": [
751
+ "icans"
752
+ ],
753
+ "icans": [
754
+ "associated neurotoxicity\nsyndrome"
755
+ ],
756
+ "department of surgical sciences": [
757
+ "ikv"
758
+ ],
759
+ "ikv": [
760
+ "department of surgical sciences"
761
+ ],
762
+ "has grouped lung and thymic neuroendocrine\ntumours": [
763
+ "nets"
764
+ ],
765
+ "nets": [
766
+ "tumors",
767
+ "has grouped lung and thymic neuroendocrine\ntumours"
768
+ ],
769
+ "small cell lung cancer": [
770
+ "sclc"
771
+ ],
772
+ "and\nlarge cell neuroendocrine carcinoma": [
773
+ "lcnec"
774
+ ],
775
+ "lcnec": [
776
+ "and\nlarge cell neuroendocrine carcinoma"
777
+ ],
778
+ "and thymic\ncarcinoid": [
779
+ "thc"
780
+ ],
781
+ "thc": [
782
+ "and thymic\ncarcinoid"
783
+ ],
784
+ "org": [
785
+ "esmo guidelines committee"
786
+ ],
787
+ "esmo guidelines committee": [
788
+ "org"
789
+ ],
790
+ "epidemiology and end results": [
791
+ "seer"
792
+ ],
793
+ "seer": [
794
+ "epidemiology and end results",
795
+ "and end results"
796
+ ],
797
+ "s syndrome": [
798
+ "cus"
799
+ ],
800
+ "cus": [
801
+ "s syndrome"
802
+ ],
803
+ "due to adrenocorticotropic hormone": [
804
+ "acth"
805
+ ],
806
+ "acth": [
807
+ "due to adrenocorticotropic hormone"
808
+ ],
809
+ "due to\ngrowth hormone-releasing hormone": [
810
+ "ghrh"
811
+ ],
812
+ "ghrh": [
813
+ "due to\ngrowth hormone-releasing hormone"
814
+ ],
815
+ "contrast": [
816
+ "liver mri"
817
+ ],
818
+ "liver mri": [
819
+ "contrast"
820
+ ],
821
+ "mediastinoscopy": [
822
+ "or ebus"
823
+ ],
824
+ "or ebus": [
825
+ "mediastinoscopy"
826
+ ],
827
+ "contrast-enhanced cross-sectional conventional": [
828
+ "radiological"
829
+ ],
830
+ "radiological": [
831
+ "contrast-enhanced cross-sectional conventional"
832
+ ],
833
+ "-labelled somatostatin analogues": [
834
+ "ssas"
835
+ ],
836
+ "ssas": [
837
+ "-labelled somatostatin analogues",
838
+ "medical options"
839
+ ],
840
+ "urinary-free cortisol": [
841
+ "ufc"
842
+ ],
843
+ "ufc": [
844
+ "urinary-free cortisol"
845
+ ],
846
+ "neuroendocrine tumor test": [
847
+ "netest"
848
+ ],
849
+ "netest": [
850
+ "neuroendocrine tumor test"
851
+ ],
852
+ "the who classification and pathological tnm": [
853
+ "ptnm"
854
+ ],
855
+ "ptnm": [
856
+ "the who classification and pathological tnm"
857
+ ],
858
+ "tumour burden and somatostatin receptor imaging": [
859
+ "sri"
860
+ ],
861
+ "sri": [
862
+ "tumour burden and somatostatin receptor imaging"
863
+ ],
864
+ "surgery\nrepresents the treatment of choice for lcs": [
865
+ "both tcs and\nacs"
866
+ ],
867
+ "both tcs and\nacs": [
868
+ "surgery\nrepresents the treatment of choice for lcs"
869
+ ],
870
+ "medical options": [
871
+ "ssas"
872
+ ],
873
+ "a combined approach": [
874
+ "sternotomy plus anterior thoracotomy"
875
+ ],
876
+ "sternotomy plus anterior thoracotomy": [
877
+ "a combined approach"
878
+ ],
879
+ "mainly cytotoxic chemotherapy": [
880
+ "cht"
881
+ ],
882
+ "cht": [
883
+ "over platinum-based doublet\nchemotherapy",
884
+ "mainly cytotoxic chemotherapy",
885
+ "the beneficial effects of adjuvant chemotherapy",
886
+ "platinum-based chemo\ntherapy",
887
+ "chemotherapy",
888
+ "the addition of the chemotherapy"
889
+ ],
890
+ "or systemic therapies": [
891
+ "with options\ndiscussed in these guidelines"
892
+ ],
893
+ "with options\ndiscussed in these guidelines": [
894
+ "or systemic therapies"
895
+ ],
896
+ "in case of\nclinical": [
897
+ "functioning syndrome"
898
+ ],
899
+ "functioning syndrome": [
900
+ "in case of\nclinical"
901
+ ],
902
+ "and the united states food and drug administration": [
903
+ "fda"
904
+ ],
905
+ "annals of oncology\n\n\n\nparathyroid hormone": [
906
+ "pth"
907
+ ],
908
+ "pth": [
909
+ "annals of oncology\n\n\n\nparathyroid hormone"
910
+ ],
911
+ "palliative surgery\nor radiofrequency ablation": [
912
+ "rfa"
913
+ ],
914
+ "rfa": [
915
+ "for these patients radiofrequency ablation",
916
+ "palliative surgery\nor radiofrequency ablation"
917
+ ],
918
+ "or cryoablation or endobronchial treatment": [
919
+ "ebt"
920
+ ],
921
+ "ebt": [
922
+ "or cryoablation or endobronchial treatment"
923
+ ],
924
+ "peptide\nreceptor radionuclide therapy": [
925
+ "prrt"
926
+ ],
927
+ "prrt": [
928
+ "peptide\nreceptor radionuclide therapy"
929
+ ],
930
+ "and interferon- a": [
931
+ "ifna"
932
+ ],
933
+ "ifna": [
934
+ "and interferon- a"
935
+ ],
936
+ "long-acting release": [
937
+ "lar"
938
+ ],
939
+ "lar": [
940
+ "long-acting release"
941
+ ],
942
+ "progression-free rate": [
943
+ "pfr"
944
+ ],
945
+ "pfr": [
946
+ "progression-free rate"
947
+ ],
948
+ "progression before enrolment": [
949
+ "luna study"
950
+ ],
951
+ "luna study": [
952
+ "progression before enrolment"
953
+ ],
954
+ "placebo-controlled trial": [
955
+ "sanet"
956
+ ],
957
+ "sanet": [
958
+ "placebo-controlled trial"
959
+ ],
960
+ "oxaliplatin combined with gemcitabine": [
961
+ "gemox"
962
+ ],
963
+ "gemox": [
964
+ "oxaliplatin combined with gemcitabine"
965
+ ],
966
+ "or capecitabine": [
967
+ "capox"
968
+ ],
969
+ "capox": [
970
+ "or capecitabine"
971
+ ],
972
+ "-fluorouracil": [
973
+ "folfox"
974
+ ],
975
+ "folfox": [
976
+ "-fluorouracil"
977
+ ],
978
+ "as alternative second-line": [
979
+ "in case of\nuncontrolled cs"
980
+ ],
981
+ "in case of\nuncontrolled cs": [
982
+ "as alternative second-line"
983
+ ],
984
+ "or mainly third-line therapy": [
985
+ "beyond\nssas and or everolimus"
986
+ ],
987
+ "beyond\nssas and or everolimus": [
988
+ "or mainly third-line therapy"
989
+ ],
990
+ "ifn- a as a potential second-line": [
991
+ "in case of uncontrolled\ncs"
992
+ ],
993
+ "in case of uncontrolled\ncs": [
994
+ "ifn- a as a potential second-line"
995
+ ],
996
+ "or mainly third-line alternative": [
997
+ "beyond ssas and or\neverolimus"
998
+ ],
999
+ "beyond ssas and or\neverolimus": [
1000
+ "or mainly third-line alternative"
1001
+ ],
1002
+ "thymic net recurrences may be local": [
1003
+ "if located in the\nanterior mediastinum"
1004
+ ],
1005
+ "if located in the\nanterior mediastinum": [
1006
+ "thymic net recurrences may be local"
1007
+ ],
1008
+ "regional": [
1009
+ "intrathoracic especially\npleural"
1010
+ ],
1011
+ "intrathoracic especially\npleural": [
1012
+ "regional"
1013
+ ],
1014
+ "an esmo\nmagnitude of clinical benefit scale": [
1015
+ "esmo-mcbs"
1016
+ ],
1017
+ "esmo-mcbs": [
1018
+ "esmo-magnitude of clinical\nbenefit",
1019
+ "esmo-magnitude of clinical benefit scale",
1020
+ "esmo-magnitude of\nclinical benefit",
1021
+ "esmomagnitude of clinical benefit scale",
1022
+ "an esmo\nmagnitude of clinical benefit scale",
1023
+ "esmo-magnitude of clinical benefit"
1024
+ ],
1025
+ "advanced carcinoids of the lung and thymus": [
1026
+ "luna"
1027
+ ],
1028
+ "luna": [
1029
+ "advanced carcinoids of the lung and thymus"
1030
+ ],
1031
+ "neuroendocrine cell hyperplasia": [
1032
+ "dipnech"
1033
+ ],
1034
+ "dipnech": [
1035
+ "neuroendocrine cell hyperplasia"
1036
+ ],
1037
+ "neuroendocrine carcinomas": [
1038
+ "carcinoid tumor"
1039
+ ],
1040
+ "carcinoid tumor": [
1041
+ "neuroendocrine carcinomas"
1042
+ ],
1043
+ "and end results": [
1044
+ "seer"
1045
+ ],
1046
+ "synchronous multiple neuroendocrine lung tumours": [
1047
+ "case series"
1048
+ ],
1049
+ "case series": [
1050
+ "synchronous multiple neuroendocrine lung tumours"
1051
+ ],
1052
+ "tumors": [
1053
+ "nets"
1054
+ ],
1055
+ "mo lanreotide autogel": [
1056
+ "lan"
1057
+ ],
1058
+ "lan": [
1059
+ "mo lanreotide autogel"
1060
+ ],
1061
+ "and temozolomide": [
1062
+ "tmz"
1063
+ ],
1064
+ "tmz": [
1065
+ "and temozolomide"
1066
+ ],
1067
+ "neuroendocrine tumours": [
1068
+ "tnets"
1069
+ ],
1070
+ "tnets": [
1071
+ "neuroendocrine tumours"
1072
+ ],
1073
+ "centre hospitalier universitaire vaudois": [
1074
+ "chuv"
1075
+ ],
1076
+ "chuv": [
1077
+ "centre hospitalier universitaire vaudois",
1078
+ "centre hospitalier universitaire\nvaudois"
1079
+ ],
1080
+ "comparing low-dose computed tomography": [
1081
+ "ldct"
1082
+ ],
1083
+ "ldct": [
1084
+ "low-dose ct",
1085
+ "comparing low-dose computed tomography"
1086
+ ],
1087
+ "such as lepidic adenocarcinomas": [
1088
+ "previously named bronchioloalveolar carcinoma"
1089
+ ],
1090
+ "previously named bronchioloalveolar carcinoma": [
1091
+ "such as lepidic adenocarcinomas"
1092
+ ],
1093
+ "how to handle": [
1094
+ "false-"
1095
+ ],
1096
+ "false-": [
1097
+ "how to handle"
1098
+ ],
1099
+ "or endoscopic\nultrasound": [
1100
+ "eus"
1101
+ ],
1102
+ "eus": [
1103
+ "or endoscopic\nultrasound"
1104
+ ],
1105
+ "the recent world health organization": [
1106
+ "who"
1107
+ ],
1108
+ "who": [
1109
+ "global",
1110
+ "global statistics",
1111
+ "world health organization",
1112
+ "vs universal",
1113
+ "the recent world health organization"
1114
+ ],
1115
+ "with its further sub-classification of": [
1116
+ "surgically resected"
1117
+ ],
1118
+ "surgically resected": [
1119
+ "with its further sub-classification of"
1120
+ ],
1121
+ "the beneficial effects of adjuvant chemotherapy": [
1122
+ "cht"
1123
+ ],
1124
+ "the categories adenocarcinoma in situ": [
1125
+ "ais"
1126
+ ],
1127
+ "ais": [
1128
+ "the categories adenocarcinoma in situ",
1129
+ "proposed\nthat ais be classified as tis"
1130
+ ],
1131
+ "minimally invasive adenocarcinoma": [
1132
+ "mia"
1133
+ ],
1134
+ "mia": [
1135
+ "minimally invasive adenocarcinoma"
1136
+ ],
1137
+ "and lepidic predominant": [
1138
+ "lep"
1139
+ ],
1140
+ "lep": [
1141
+ "and lepidic predominant"
1142
+ ],
1143
+ "of fluorodeoxyglucose-positron emission tomography": [
1144
+ "fdg-pet"
1145
+ ],
1146
+ "fdg-pet": [
1147
+ "of fluorodeoxyglucose-positron emission tomography"
1148
+ ],
1149
+ "the rate of nos": [
1150
+ "not otherwise\nspecified"
1151
+ ],
1152
+ "not otherwise\nspecified": [
1153
+ "the rate of nos"
1154
+ ],
1155
+ "the union for\ninternational cancer control": [
1156
+ "uicc"
1157
+ ],
1158
+ "uicc": [
1159
+ "union for international cancer control",
1160
+ "union for international\ncancer control",
1161
+ "the union for\ninternational cancer control"
1162
+ ],
1163
+ "node and metastasis": [
1164
+ "tnm"
1165
+ ],
1166
+ "tnm": [
1167
+ "tumourenodeemetastasis",
1168
+ "node and metastasis"
1169
+ ],
1170
+ "proposed\nthat ais be classified as tis": [
1171
+ "ais"
1172
+ ],
1173
+ "the display is best with wide": [
1174
+ "lung"
1175
+ ],
1176
+ "lung": [
1177
+ "the display is best with wide"
1178
+ ],
1179
+ "a should be restricted to the same histological": [
1180
+ "sub"
1181
+ ],
1182
+ "sub": [
1183
+ "research support as",
1184
+ "a should be restricted to the same histological"
1185
+ ],
1186
+ "videoassisted mediastinoscopy": [
1187
+ "vam"
1188
+ ],
1189
+ "vam": [
1190
+ "videoassisted mediastinoscopy"
1191
+ ],
1192
+ "whereas the american college of chest physicians": [
1193
+ "accp"
1194
+ ],
1195
+ "accp": [
1196
+ "whereas the american college of chest physicians",
1197
+ "the\namerican college of chest physicians"
1198
+ ],
1199
+ "adjuvant chemotherapy": [
1200
+ "radiotherapy"
1201
+ ],
1202
+ "radiotherapy": [
1203
+ "adjuvant chemotherapy"
1204
+ ],
1205
+ "or a video-assisted thoracoscopic surgery": [
1206
+ "vats"
1207
+ ],
1208
+ "vats": [
1209
+ "or a video-assisted thoracoscopic surgery"
1210
+ ],
1211
+ "based on the lung cancer study group": [
1212
+ "lcsg"
1213
+ ],
1214
+ "lcsg": [
1215
+ "based on the lung cancer study group"
1216
+ ],
1217
+ "research based on large databases suggest a": [
1218
+ "limited"
1219
+ ],
1220
+ "limited": [
1221
+ "research based on large databases suggest a"
1222
+ ],
1223
+ "acc guidelines\n\nneed for coronary\nintervention": [
1224
+ "cabg or pci"
1225
+ ],
1226
+ "cabg or pci": [
1227
+ "acc guidelines\n\nneed for coronary\nintervention"
1228
+ ],
1229
+ "high risk surgery": [
1230
+ "including\nlobectomy or pneumonectomy"
1231
+ ],
1232
+ "including\nlobectomy or pneumonectomy": [
1233
+ "high risk surgery"
1234
+ ],
1235
+ "disease": [
1236
+ "stage ii and\niii"
1237
+ ],
1238
+ "stage ii and\niii": [
1239
+ "disease"
1240
+ ],
1241
+ "sabr or stereotactic body radiotherapy": [
1242
+ "sbrt"
1243
+ ],
1244
+ "in those with proven recurrence": [
1245
+ "or a high suspicion"
1246
+ ],
1247
+ "or a high suspicion": [
1248
+ "in those with proven recurrence"
1249
+ ],
1250
+ "for these patients radiofrequency ablation": [
1251
+ "rfa"
1252
+ ],
1253
+ "clinical trials": [
1254
+ "rcts"
1255
+ ],
1256
+ "the induction regimen of chemoradiotherapy": [
1257
+ "crt"
1258
+ ],
1259
+ "crt": [
1260
+ "the induction regimen of chemoradiotherapy"
1261
+ ],
1262
+ "sequential crt": [
1263
+ "induction cht followed by rt"
1264
+ ],
1265
+ "induction cht followed by rt": [
1266
+ "sequential crt"
1267
+ ],
1268
+ "- immunotherapy is being studied in early nsclc as": [
1269
+ "neo"
1270
+ ],
1271
+ "neo": [
1272
+ "- immunotherapy is being studied in early nsclc as",
1273
+ "immunotherapy is being studied in early nsclc as",
1274
+ "the\nimmune strategy in the"
1275
+ ],
1276
+ "cl\n\ntreatment of locally advanced stage": [
1277
+ "stage ill"
1278
+ ],
1279
+ "stage ill": [
1280
+ "cl\n\ntreatment of locally advanced stage"
1281
+ ],
1282
+ "immunotherapy is being studied in early nsclc as": [
1283
+ "neo"
1284
+ ],
1285
+ "controlled trial of good methodological quality": [
1286
+ "low potential for bias"
1287
+ ],
1288
+ "low potential for bias": [
1289
+ "controlled trial of good methodological quality"
1290
+ ],
1291
+ "or imaging": [
1292
+ "preferably ct"
1293
+ ],
1294
+ "preferably ct": [
1295
+ "or imaging"
1296
+ ],
1297
+ "european society of gastrointestinal endoscopy": [
1298
+ "esge"
1299
+ ],
1300
+ "esge": [
1301
+ "european society of gastrointestinal endoscopy"
1302
+ ],
1303
+ "and the european\nsociety of thoracic surgeons": [
1304
+ "ests"
1305
+ ],
1306
+ "ests": [
1307
+ "and the european\nsociety of thoracic surgeons",
1308
+ "and european society of thoracic surgeons"
1309
+ ],
1310
+ "gv scagliotti": [
1311
+ "eds"
1312
+ ],
1313
+ "eds": [
1314
+ "gv scagliotti"
1315
+ ],
1316
+ "the thoracic surgery scoring\nsystem": [
1317
+ "thoracoscore"
1318
+ ],
1319
+ "thoracoscore": [
1320
+ "the thoracic surgery scoring\nsystem",
1321
+ "the thoracic surgery scoring system"
1322
+ ],
1323
+ "stereotactic body radiotherapy": [
1324
+ "sbrt"
1325
+ ],
1326
+ "respiratory oncology unit": [
1327
+ "pulmonology"
1328
+ ],
1329
+ "pulmonology": [
1330
+ "respiratory oncology",
1331
+ "respiratory oncology unit"
1332
+ ],
1333
+ "edegem": [
1334
+ "antwerp"
1335
+ ],
1336
+ "antwerp": [
1337
+ "edegem"
1338
+ ],
1339
+ "centre hospitalier universitaire\nvaudois": [
1340
+ "chuv"
1341
+ ],
1342
+ "early-stage nsclc": [
1343
+ "stages i ii"
1344
+ ],
1345
+ "stages i ii": [
1346
+ "early-stage nsclc"
1347
+ ],
1348
+ "locally advanced nsclc": [
1349
+ "stage iii"
1350
+ ],
1351
+ "stage iii": [
1352
+ "treatment of locally advanced stage",
1353
+ "unresectable nsclc",
1354
+ "and unresectable locally advanced",
1355
+ "locally advanced nsclc"
1356
+ ],
1357
+ "in paral\npractice guidelines": [
1358
+ "cpgs"
1359
+ ],
1360
+ "cpgs": [
1361
+ "in paral\npractice guidelines"
1362
+ ],
1363
+ "and a general consen\nconsensus process": [
1364
+ "see panel members listed in the appendix"
1365
+ ],
1366
+ "see panel members listed in the appendix": [
1367
+ "experts were involved in this\nconsensus process",
1368
+ "and a general consen\nconsensus process"
1369
+ ],
1370
+ "experts were involved in this\nconsensus process": [
1371
+ "see panel members listed in the appendix"
1372
+ ],
1373
+ "controlled trials": [
1374
+ "rcts"
1375
+ ],
1376
+ "the\namerican college of chest physicians": [
1377
+ "accp"
1378
+ ],
1379
+ "as relative value depends on personal": [
1380
+ "usually unexplained or unquantifiable"
1381
+ ],
1382
+ "usually unexplained or unquantifiable": [
1383
+ "as relative value depends on personal"
1384
+ ],
1385
+ "respiratory literature": [
1386
+ "especially on exercise\ntesting"
1387
+ ],
1388
+ "especially on exercise\ntesting": [
1389
+ "respiratory literature"
1390
+ ],
1391
+ "use of the revised cardiac risk index": [
1392
+ "rcri"
1393
+ ],
1394
+ "rcri": [
1395
+ "use of the revised cardiac risk index"
1396
+ ],
1397
+ "and european society of thoracic surgeons": [
1398
+ "ests"
1399
+ ],
1400
+ "for sub-lobar resection": [
1401
+ "wide wedge resection or anatomical segmentectomy"
1402
+ ],
1403
+ "wide wedge resection or anatomical segmentectomy": [
1404
+ "for sub-lobar resection"
1405
+ ],
1406
+ "for which patients is limited": [
1407
+ "sub-lobar"
1408
+ ],
1409
+ "sub-lobar": [
1410
+ "for which patients is limited",
1411
+ "special articles\n\n\n\nfor which patients is limited"
1412
+ ],
1413
+ "especially those with ground-glass\nopacity": [
1414
+ "ggo"
1415
+ ],
1416
+ "ggo": [
1417
+ "especially those with ground-glass\nopacity"
1418
+ ],
1419
+ "special articles\n\n\n\nfor which patients is limited": [
1420
+ "sub-lobar"
1421
+ ],
1422
+ "other approaches such as local ablative": [
1423
+ "sabr"
1424
+ ],
1425
+ "sabr": [
1426
+ "other approaches such as local ablative",
1427
+ "solidative stereotactic ablative radiotherapy"
1428
+ ],
1429
+ "some trials": [
1430
+ "ialt"
1431
+ ],
1432
+ "ialt": [
1433
+ "some trials"
1434
+ ],
1435
+ "anatomical resection": [
1436
+ "lobectomy"
1437
+ ],
1438
+ "lobectomy": [
1439
+ "anatomical resection"
1440
+ ],
1441
+ "european society for\nmedical oncology": [
1442
+ "esmo"
1443
+ ],
1444
+ "boehringer ingelheim and astrazeneca": [
1445
+ "for lectures"
1446
+ ],
1447
+ "for lectures": [
1448
+ "boehringer ingelheim and astrazeneca"
1449
+ ],
1450
+ "results of\nthe initial": [
1451
+ "prevalence"
1452
+ ],
1453
+ "prevalence": [
1454
+ "results of\nthe initial",
1455
+ "results of the\ninitial"
1456
+ ],
1457
+ "results of the\ninitial": [
1458
+ "prevalence"
1459
+ ],
1460
+ "results\nof the initial": [
1461
+ "prevalance"
1462
+ ],
1463
+ "prevalance": [
1464
+ "results\nof the initial"
1465
+ ],
1466
+ "the thoracic surgery scoring system": [
1467
+ "thoracoscore"
1468
+ ],
1469
+ "robotic lobectomy for non-small cell lung cancer": [
1470
+ "nsclc"
1471
+ ],
1472
+ "fdg-pet and stereotactic body radiotherapy": [
1473
+ "sbrt"
1474
+ ],
1475
+ "respiratory oncology": [
1476
+ "pulmonology"
1477
+ ],
1478
+ "vrije\nuniversity medical centre": [
1479
+ "vumc"
1480
+ ],
1481
+ "vumc": [
1482
+ "vrije\nuniversity medical centre",
1483
+ "university medical centre"
1484
+ ],
1485
+ "university medical centre": [
1486
+ "vumc"
1487
+ ],
1488
+ "phase iii randomised clinical trial": [
1489
+ "rct"
1490
+ ],
1491
+ "platinum-based doublet chemotherapy": [
1492
+ "pbc"
1493
+ ],
1494
+ "pbc": [
1495
+ "five cycles of\n\ntremelimumab",
1496
+ "platinum-based doublet chemotherapy"
1497
+ ],
1498
+ "carboplatin": [
1499
+ "arm a",
1500
+ "arm b"
1501
+ ],
1502
+ "arm a": [
1503
+ "carboplatin"
1504
+ ],
1505
+ "arm b": [
1506
+ "carboplatin"
1507
+ ],
1508
+ "pbc significantly improved pfs": [
1509
+ "primary\nendpoint"
1510
+ ],
1511
+ "primary\nendpoint": [
1512
+ "pbc significantly improved pfs"
1513
+ ],
1514
+ "pbc\nsignificantly improved pfs": [
1515
+ "primary endpoint"
1516
+ ],
1517
+ "primary endpoint": [
1518
+ "significantly improved os",
1519
+ "level",
1520
+ "-year os",
1521
+ "pbc\nsignificantly improved pfs"
1522
+ ],
1523
+ "besides immune checkpoint\n\ninhibitor": [
1524
+ "ici"
1525
+ ],
1526
+ "ici": [
1527
+ "besides immune checkpoint\n\ninhibitor",
1528
+ "and have no prior immune checkpoint inhibitor"
1529
+ ],
1530
+ "esmo-magnitude of clinical benefit scale": [
1531
+ "mcbs",
1532
+ "esmo-mcbs"
1533
+ ],
1534
+ "mcbs": [
1535
+ "esmo-magnitude of clinical benefit scale"
1536
+ ],
1537
+ "five cycles of\n\ntremelimumab": [
1538
+ "pbc"
1539
+ ],
1540
+ "platinum-based chemo\ntherapy": [
1541
+ "cht"
1542
+ ],
1543
+ "food and drug administration": [
1544
+ "fda"
1545
+ ],
1546
+ "european medicines agency": [
1547
+ "ema"
1548
+ ],
1549
+ "of tumour cells": [
1550
+ "tcs"
1551
+ ],
1552
+ "tcs": [
1553
+ "of tumour cells"
1554
+ ],
1555
+ "level": [
1556
+ "primary endpoint"
1557
+ ],
1558
+ "tumour treating\nfields": [
1559
+ "ttfields"
1560
+ ],
1561
+ "ttfields": [
1562
+ "tumour treating\nfields"
1563
+ ],
1564
+ "significantly improved os": [
1565
+ "primary endpoint"
1566
+ ],
1567
+ "ioanna ntai and claire bramley": [
1568
+ "esmo guidelines staff"
1569
+ ],
1570
+ "esmo guidelines staff": [
1571
+ "ioanna ntai and claire bramley",
1572
+ "jennifer\nlamarre and guy atchison"
1573
+ ],
1574
+ "valerie laforest": [
1575
+ "esmo\nguidelines staff"
1576
+ ],
1577
+ "esmo\nguidelines staff": [
1578
+ "valerie laforest"
1579
+ ],
1580
+ "nicola latino and\nfrancesca chiovaro": [
1581
+ "esmo scientific affairs staff"
1582
+ ],
1583
+ "esmo scientific affairs staff": [
1584
+ "nicola\nlatino and francesca chiovaro",
1585
+ "nicola latino",
1586
+ "nicola\nlatino",
1587
+ "nicola latino and\nfrancesca chiovaro"
1588
+ ],
1589
+ "bristol\nmyers squibb": [
1590
+ "bms"
1591
+ ],
1592
+ "the european society for medical\noncology": [
1593
+ "esmo"
1594
+ ],
1595
+ "and the\neuropean thoracic oncology platform": [
1596
+ "foundation council\nmember"
1597
+ ],
1598
+ "foundation council\nmember": [
1599
+ "and the\neuropean thoracic oncology platform"
1600
+ ],
1601
+ "with a platinum-containing\nregimen": [
1602
+ "ipsos"
1603
+ ],
1604
+ "ipsos": [
1605
+ "with a platinum-containing\nregimen"
1606
+ ],
1607
+ "esmo clinical practice guideline": [
1608
+ "cpg"
1609
+ ],
1610
+ "cpg": [
1611
+ "esmo clinical practice guideline"
1612
+ ],
1613
+ "tyrosine kinase inhibitors": [
1614
+ "tkis"
1615
+ ],
1616
+ "tkis": [
1617
+ "tyrosine kinase inhibitors"
1618
+ ],
1619
+ "by next-generation sequencing": [
1620
+ "ngs"
1621
+ ],
1622
+ "ngs": [
1623
+ "multiplex platforms",
1624
+ "such as next-generation sequencing",
1625
+ "by next-generation sequencing"
1626
+ ],
1627
+ "egfr fish or immunohistochemistry": [
1628
+ "ihc"
1629
+ ],
1630
+ "positive anaplastic lymphoma kinase": [
1631
+ "alk"
1632
+ ],
1633
+ "or neurotrophic tyrosine\nreceptor kinase": [
1634
+ "ntrk"
1635
+ ],
1636
+ "ntrk": [
1637
+ "and the neurotrophic receptor tyrosine\nkinase",
1638
+ "or neurotrophic tyrosine\nreceptor kinase"
1639
+ ],
1640
+ "detection is reliable by\nin situ hybridisation": [
1641
+ "ish"
1642
+ ],
1643
+ "ish": [
1644
+ "detection is reliable by\nin situ hybridisation"
1645
+ ],
1646
+ "mesenchymal-epithelial transition": [
1647
+ "met"
1648
+ ],
1649
+ "met": [
1650
+ "mesenchymal-epithelial transition"
1651
+ ],
1652
+ "cell-free dna": [
1653
+ "cfdna"
1654
+ ],
1655
+ "cfdna": [
1656
+ "liquid biopsy",
1657
+ "cell-free dna"
1658
+ ],
1659
+ "multiplex platforms": [
1660
+ "ngs"
1661
+ ],
1662
+ "liquid biopsy": [
1663
+ "cfdna"
1664
+ ],
1665
+ "scan of\nthe chest and upper abdomen": [
1666
+ "including the liver and\nadrenal glands"
1667
+ ],
1668
+ "including the liver and\nadrenal glands": [
1669
+ "scan of\nthe chest and upper abdomen"
1670
+ ],
1671
+ "imaging of the central nervous system": [
1672
+ "cns"
1673
+ ],
1674
+ "cns": [
1675
+ "imaging of the central nervous system"
1676
+ ],
1677
+ "e\ndeoxy-d-glucose": [
1678
+ "fdg"
1679
+ ],
1680
+ "fdg": [
1681
+ "e\ndeoxy-d-glucose"
1682
+ ],
1683
+ "union for international\ncancer control": [
1684
+ "uicc"
1685
+ ],
1686
+ "tumourenodeemetastasis": [
1687
+ "tnm",
1688
+ "staging and risk assessment\n\n\nthe tnm"
1689
+ ],
1690
+ "over platinum-based doublet\nchemotherapy": [
1691
+ "cht"
1692
+ ],
1693
+ "quality of life and progression-free survival": [
1694
+ "pfs"
1695
+ ],
1696
+ "phase iib\nrandomised controlled trial": [
1697
+ "rct"
1698
+ ],
1699
+ "demonstrating a superior\nmedian pfs": [
1700
+ "mpfs"
1701
+ ],
1702
+ "mpfs": [
1703
+ "demonstrating a superior\nmedian pfs"
1704
+ ],
1705
+ "and median os": [
1706
+ "mos"
1707
+ ],
1708
+ "mos": [
1709
+ "the malaysian oncological society",
1710
+ "malaysia",
1711
+ "and median os"
1712
+ ],
1713
+ "systemic progression\n\nlocal treatment": [
1714
+ "surgery or ft"
1715
+ ],
1716
+ "surgery or ft": [
1717
+ "systemic progression\n\nlocal treatment"
1718
+ ],
1719
+ "mpositive resistant disease": [
1720
+ "occurring in approximately half of\nthe patients"
1721
+ ],
1722
+ "occurring in approximately half of\nthe patients": [
1723
+ "mpositive resistant disease"
1724
+ ],
1725
+ "not european medicines agency": [
1726
+ "ema"
1727
+ ],
1728
+ "single-agent": [
1729
+ "third-generation"
1730
+ ],
1731
+ "third-generation": [
1732
+ "single-agent"
1733
+ ],
1734
+ "ensartinib": [
1735
+ "not ema approved",
1736
+ "not ema\napproved"
1737
+ ],
1738
+ "not ema\napproved": [
1739
+ "ensartinib"
1740
+ ],
1741
+ "j-alex": [
1742
+ "japan"
1743
+ ],
1744
+ "japan": [
1745
+ "j-alex",
1746
+ "jsmo"
1747
+ ],
1748
+ "and\nalesia": [
1749
+ "asia"
1750
+ ],
1751
+ "asia": [
1752
+ "and\nalesia"
1753
+ ],
1754
+ "and continue targeted": [
1755
+ "not mandatory for decision"
1756
+ ],
1757
+ "not mandatory for decision": [
1758
+ "and continue targeted"
1759
+ ],
1760
+ "interstitial lung disease": [
1761
+ "ild"
1762
+ ],
1763
+ "ild": [
1764
+ "interstitial lung disease"
1765
+ ],
1766
+ "not ema approved": [
1767
+ "ensartinib"
1768
+ ],
1769
+ "mainly altered lipid levels": [
1770
+ "aes"
1771
+ ],
1772
+ "alectinib was superior to single-agent cht": [
1773
+ "docetaxel or pemetrexed"
1774
+ ],
1775
+ "docetaxel or pemetrexed": [
1776
+ "alectinib was superior to single-agent cht"
1777
+ ],
1778
+ "entrectinib received food and\ndrug administration": [
1779
+ "fda"
1780
+ ],
1781
+ "the\nmedian duration of response": [
1782
+ "mdor"
1783
+ ],
1784
+ "mdor": [
1785
+ "the\nmedian duration of response"
1786
+ ],
1787
+ "tropomyosin receptor tyrosine kinase": [
1788
+ "trk"
1789
+ ],
1790
+ "trk": [
1791
+ "tropomyosin receptor tyrosine kinase"
1792
+ ],
1793
+ "disease progression\n\nlocal treatment": [
1794
+ "surgery or rt"
1795
+ ],
1796
+ "surgery or rt": [
1797
+ "local treatment",
1798
+ "oligoprogression\n\nlocal treatment",
1799
+ "disease progression\n\nlocal treatment"
1800
+ ],
1801
+ "or combination therapy with a mek inhibitor": [
1802
+ "trametinib"
1803
+ ],
1804
+ "trametinib": [
1805
+ "or combination therapy with a mek inhibitor"
1806
+ ],
1807
+ "local treatment": [
1808
+ "surgery or rt"
1809
+ ],
1810
+ "a rearranged during transfection": [
1811
+ "ret"
1812
+ ],
1813
+ "ret": [
1814
+ "a rearranged during transfection"
1815
+ ],
1816
+ "trastuzumab deruxtecan": [
1817
+ "fda\napproved"
1818
+ ],
1819
+ "fda\napproved": [
1820
+ "trastuzumab deruxtecan"
1821
+ ],
1822
+ "the\nkirsten rat sarcoma virus": [
1823
+ "kras"
1824
+ ],
1825
+ "kras": [
1826
+ "the\nkirsten rat sarcoma virus"
1827
+ ],
1828
+ "data regarding the role of local ablative therapy": [
1829
+ "lat"
1830
+ ],
1831
+ "lat": [
1832
+ "data regarding the role of local ablative therapy"
1833
+ ],
1834
+ "one open-label phase iii rct": [
1835
+ "sindas"
1836
+ ],
1837
+ "sindas": [
1838
+ "one open-label phase iii rct"
1839
+ ],
1840
+ "in particular with the use\nof modern technologies": [
1841
+ "robotic systems"
1842
+ ],
1843
+ "robotic systems": [
1844
+ "in particular with the use\nof modern technologies"
1845
+ ],
1846
+ "esmo-magnitude of\nclinical benefit": [
1847
+ "esmo-mcbs"
1848
+ ],
1849
+ "may\nbenefit from lat": [
1850
+ "high-dose rt or surgery"
1851
+ ],
1852
+ "high-dose rt or surgery": [
1853
+ "from lat",
1854
+ "may\nbenefit from lat"
1855
+ ],
1856
+ "jennifer\nlamarre and guy atchison": [
1857
+ "esmo guidelines staff"
1858
+ ],
1859
+ "nicola\nlatino": [
1860
+ "esmo scientific affairs staff"
1861
+ ],
1862
+ "and dr svetlana jezdic": [
1863
+ "esmo\nmedical affairs advisor",
1864
+ "esmo medical affairs staff"
1865
+ ],
1866
+ "esmo\nmedical affairs advisor": [
1867
+ "and dr svetlana jezdic"
1868
+ ],
1869
+ "bristol-myers\nsquibb": [
1870
+ "bms"
1871
+ ],
1872
+ "asian\nthoracic oncology research group": [
1873
+ "atorg"
1874
+ ],
1875
+ "atorg": [
1876
+ "asian\nthoracic oncology research group"
1877
+ ],
1878
+ "chinese lung\ncancer research foundation limited": [
1879
+ "clcrf"
1880
+ ],
1881
+ "clcrf": [
1882
+ "chinese lung\ncancer research foundation limited"
1883
+ ],
1884
+ "chinese society of clinical oncology": [
1885
+ "csco"
1886
+ ],
1887
+ "csco": [
1888
+ "chinese society of clinical oncology"
1889
+ ],
1890
+ "hong kong cancer fund": [
1891
+ "hkcf"
1892
+ ],
1893
+ "hkcf": [
1894
+ "hong kong cancer fund"
1895
+ ],
1896
+ "hong kong cancer therapy society": [
1897
+ "hkcts"
1898
+ ],
1899
+ "hkcts": [
1900
+ "hong kong cancer therapy society"
1901
+ ],
1902
+ "prep school": [
1903
+ "hong kong"
1904
+ ],
1905
+ "hong kong": [
1906
+ "prep school"
1907
+ ],
1908
+ "s education resource": [
1909
+ "per"
1910
+ ],
1911
+ "per": [
1912
+ "s education resource"
1913
+ ],
1914
+ "partnerships in international medical education": [
1915
+ "prime"
1916
+ ],
1917
+ "prime": [
1918
+ "partnerships in international medical education"
1919
+ ],
1920
+ "llc": [
1921
+ "rmei"
1922
+ ],
1923
+ "rmei": [
1924
+ "llc"
1925
+ ],
1926
+ "research\nto practice": [
1927
+ "rtp"
1928
+ ],
1929
+ "rtp": [
1930
+ "research\nto practice"
1931
+ ],
1932
+ "research": [
1933
+ "sakk",
1934
+ "ukcccr"
1935
+ ],
1936
+ "sakk": [
1937
+ "research"
1938
+ ],
1939
+ "international breast cancer study group": [
1940
+ "ibcsg"
1941
+ ],
1942
+ "ibcsg": [
1943
+ "international breast cancer study group"
1944
+ ],
1945
+ "s\nde clinique": [
1946
+ "asmac"
1947
+ ],
1948
+ "asmac": [
1949
+ "s\nde clinique"
1950
+ ],
1951
+ "rzte": [
1952
+ "vsao"
1953
+ ],
1954
+ "vsao": [
1955
+ "rzte"
1956
+ ],
1957
+ "decins suisses": [
1958
+ "fmh"
1959
+ ],
1960
+ "fmh": [
1961
+ "decins suisses"
1962
+ ],
1963
+ "cancers": [
1964
+ "basel"
1965
+ ],
1966
+ "basel": [
1967
+ "cancers"
1968
+ ],
1969
+ "relay": [
1970
+ "cancer"
1971
+ ],
1972
+ "non-small-cell lung cancer": [
1973
+ "alesia",
1974
+ "nsclc"
1975
+ ],
1976
+ "alesia": [
1977
+ "non-small-cell lung cancer"
1978
+ ],
1979
+ "crizotinib-pretreated anaplastic lymphoma kinase": [
1980
+ "alk"
1981
+ ],
1982
+ "advanced non-small-cell lung cancer": [
1983
+ "nsclc"
1984
+ ],
1985
+ "fda prescribing information - rozlytrek": [
1986
+ "entrectinib"
1987
+ ],
1988
+ "entrectinib": [
1989
+ "fda prescribing information - rozlytrek"
1990
+ ],
1991
+ "retsevmo - summary of opinion": [
1992
+ "chmp"
1993
+ ],
1994
+ "chmp": [
1995
+ "tabrecta - summary of opinion",
1996
+ "retsevmo - summary of opinion",
1997
+ "products for human use"
1998
+ ],
1999
+ "tabrecta - summary of opinion": [
2000
+ "chmp"
2001
+ ],
2002
+ "prescribing information - rybrevant": [
2003
+ "amivantamab-vmjw"
2004
+ ],
2005
+ "amivantamab-vmjw": [
2006
+ "prescribing information - rybrevant"
2007
+ ],
2008
+ "solidative stereotactic ablative radiotherapy": [
2009
+ "sabr"
2010
+ ],
2011
+ "the european society for medical oncology": [
2012
+ "esmo"
2013
+ ],
2014
+ "to produce the pan-asian adapted": [
2015
+ "paga"
2016
+ ],
2017
+ "paga": [
2018
+ "to produce the pan-asian adapted"
2019
+ ],
2020
+ "indonesia": [
2021
+ "ishmo"
2022
+ ],
2023
+ "ishmo": [
2024
+ "indonesia"
2025
+ ],
2026
+ "india": [
2027
+ "ismpo"
2028
+ ],
2029
+ "ismpo": [
2030
+ "india"
2031
+ ],
2032
+ "jsmo": [
2033
+ "japan",
2034
+ "the\njapanese society of medical oncology"
2035
+ ],
2036
+ "korea": [
2037
+ "ksmo"
2038
+ ],
2039
+ "ksmo": [
2040
+ "korea"
2041
+ ],
2042
+ "malaysia": [
2043
+ "mos"
2044
+ ],
2045
+ "the philippines": [
2046
+ "psmo"
2047
+ ],
2048
+ "psmo": [
2049
+ "the philippines",
2050
+ "the philippine society of\nmedical oncology",
2051
+ "and philippine society of medical\noncology"
2052
+ ],
2053
+ "singapore": [
2054
+ "sso"
2055
+ ],
2056
+ "sso": [
2057
+ "the singapore society of\noncology",
2058
+ "singapore"
2059
+ ],
2060
+ "taiwan": [
2061
+ "tos"
2062
+ ],
2063
+ "tos": [
2064
+ "the taiwan oncology society",
2065
+ "taiwan"
2066
+ ],
2067
+ "and thailand": [
2068
+ "tsco"
2069
+ ],
2070
+ "tsco": [
2071
+ "and thailand",
2072
+ "and the\nthai society of clinical oncology"
2073
+ ],
2074
+ "and the neurotrophic receptor tyrosine\nkinase": [
2075
+ "ntrk"
2076
+ ],
2077
+ "esmo open\n\n\n\nrecommendation": [
2078
+ "gor"
2079
+ ],
2080
+ "gor": [
2081
+ "esmo open\n\n\n\nrecommendation"
2082
+ ],
2083
+ "esmomagnitude of clinical benefit scale": [
2084
+ "esmo-mcbs"
2085
+ ],
2086
+ "the\njapanese society of medical oncology": [
2087
+ "jsmo"
2088
+ ],
2089
+ "the malaysian oncological society": [
2090
+ "mos"
2091
+ ],
2092
+ "the philippine society of\nmedical oncology": [
2093
+ "psmo"
2094
+ ],
2095
+ "the singapore society of\noncology": [
2096
+ "sso"
2097
+ ],
2098
+ "the taiwan oncology society": [
2099
+ "tos"
2100
+ ],
2101
+ "and the\nthai society of clinical oncology": [
2102
+ "tsco"
2103
+ ],
2104
+ "only two of the six\nexpert members from the ksmo": [
2105
+ "tmk and hrk"
2106
+ ],
2107
+ "tmk and hrk": [
2108
+ "only two of the six\nexpert members from the ksmo"
2109
+ ],
2110
+ "performance status": [
2111
+ "ecog ps"
2112
+ ],
2113
+ "ecog ps": [
2114
+ "performance status"
2115
+ ],
2116
+ "scan of the chest and upper abdomen": [
2117
+ "including the liver and adrenal glands"
2118
+ ],
2119
+ "including the liver and adrenal glands": [
2120
+ "scan of the chest and upper abdomen"
2121
+ ],
2122
+ "resonance imaging": [
2123
+ "mri"
2124
+ ],
2125
+ "mri": [
2126
+ "and\na magnetic resonance imaging",
2127
+ "resonance imaging"
2128
+ ],
2129
+ "-positron emission topography": [
2130
+ "pet"
2131
+ ],
2132
+ "pet": [
2133
+ "-positron emission topography",
2134
+ "of whom had undergone positron\nemission tomography"
2135
+ ],
2136
+ "union for international cancer control": [
2137
+ "uicc"
2138
+ ],
2139
+ "third-generation egfr tkis": [
2140
+ "such as osimertinib"
2141
+ ],
2142
+ "such as osimertinib": [
2143
+ "generation tki",
2144
+ "third-generation egfr tkis"
2145
+ ],
2146
+ "generation tki": [
2147
+ "such as osimertinib"
2148
+ ],
2149
+ "from lat": [
2150
+ "high-dose rt or surgery"
2151
+ ],
2152
+ "such as next-generation sequencing": [
2153
+ "ngs"
2154
+ ],
2155
+ "serious adverse events": [
2156
+ "saes"
2157
+ ],
2158
+ "saes": [
2159
+ "serious adverse events"
2160
+ ],
2161
+ "reported improved\nprogression-free survival": [
2162
+ "pfs"
2163
+ ],
2164
+ "which had an overall response rate": [
2165
+ "orr"
2166
+ ],
2167
+ "the median\nduration of response": [
2168
+ "dor"
2169
+ ],
2170
+ "esmo-magnitude of clinical benefit": [
2171
+ "esmo-mcbs"
2172
+ ],
2173
+ "esmo-magnitude of clinical\nbenefit": [
2174
+ "esmo-mcbs"
2175
+ ],
2176
+ "the addition of the chemotherapy": [
2177
+ "cht"
2178
+ ],
2179
+ "treatment-related aes": [
2180
+ "traes"
2181
+ ],
2182
+ "traes": [
2183
+ "treatment-related aes"
2184
+ ],
2185
+ "and have no prior immune checkpoint inhibitor": [
2186
+ "ici"
2187
+ ],
2188
+ "the food and drug administration": [
2189
+ "fda"
2190
+ ],
2191
+ "s national medical products\nadministration": [
2192
+ "nsmpa"
2193
+ ],
2194
+ "nsmpa": [
2195
+ "s national medical products\nadministration"
2196
+ ],
2197
+ "ishmo\n\n\nthe jaminan kesehatan nasional": [
2198
+ "jkn"
2199
+ ],
2200
+ "jkn": [
2201
+ "ishmo\n\n\nthe jaminan kesehatan nasional"
2202
+ ],
2203
+ "there is no regulation of partial coverage": [
2204
+ "co-payment"
2205
+ ],
2206
+ "co-payment": [
2207
+ "there is no regulation of partial coverage"
2208
+ ],
2209
+ "esmo open\n\n\n\nprogram": [
2210
+ "pap"
2211
+ ],
2212
+ "pap": [
2213
+ "esmo open\n\n\n\nprogram"
2214
+ ],
2215
+ "mandatory national health insurance": [
2216
+ "nhi"
2217
+ ],
2218
+ "nhi": [
2219
+ "mandatory national health insurance"
2220
+ ],
2221
+ "this includes ngs panel tests": [
2222
+ "partially reimbursed"
2223
+ ],
2224
+ "partially reimbursed": [
2225
+ "this includes ngs panel tests"
2226
+ ],
2227
+ "social\nsecurity and government officer": [
2228
+ "csmbs"
2229
+ ],
2230
+ "csmbs": [
2231
+ "social\nsecurity and government officer"
2232
+ ],
2233
+ "alk inhibitors": [
2234
+ "ceritinib and brigatinib only"
2235
+ ],
2236
+ "ceritinib and brigatinib only": [
2237
+ "alk inhibitors"
2238
+ ],
2239
+ "and atezolizumab": [
2240
+ "in the\nsecond-line setting"
2241
+ ],
2242
+ "in the\nsecond-line setting": [
2243
+ "and atezolizumab"
2244
+ ],
2245
+ "erlotinib and osimertinib": [
2246
+ "second-line with reimbursement\nthrough the csmbs"
2247
+ ],
2248
+ "second-line with reimbursement\nthrough the csmbs": [
2249
+ "erlotinib and osimertinib"
2250
+ ],
2251
+ "and the alk inhibitors ceritinib and\nbrigatinib": [
2252
+ "first-line"
2253
+ ],
2254
+ "first-line": [
2255
+ "and the alk inhibitors ceritinib and\nbrigatinib"
2256
+ ],
2257
+ "german": [
2258
+ "merck"
2259
+ ],
2260
+ "thoracic oncology research\ngroup": [
2261
+ "torg"
2262
+ ],
2263
+ "torg": [
2264
+ "thoracic oncology research\ngroup"
2265
+ ],
2266
+ "and west japan oncology group": [
2267
+ "wjog"
2268
+ ],
2269
+ "wjog": [
2270
+ "and west japan oncology group"
2271
+ ],
2272
+ "product samples": [
2273
+ "nonrenumerated"
2274
+ ],
2275
+ "nonrenumerated": [
2276
+ "product samples"
2277
+ ],
2278
+ "and philippine society of medical\noncology": [
2279
+ "psmo"
2280
+ ],
2281
+ "trial steering committee": [
2282
+ "tsc"
2283
+ ],
2284
+ "tsc": [
2285
+ "trial steering committee"
2286
+ ],
2287
+ "independent data monitoring committee": [
2288
+ "idmc"
2289
+ ],
2290
+ "idmc": [
2291
+ "independent data monitoring committee"
2292
+ ],
2293
+ "ireland oesophagogastric group": [
2294
+ "ukiog"
2295
+ ],
2296
+ "ukiog": [
2297
+ "ireland oesophagogastric group"
2298
+ ],
2299
+ "celgene": [
2300
+ "bms"
2301
+ ],
2302
+ "hellenic cooperative oncology group": [
2303
+ "hecog"
2304
+ ],
2305
+ "hecog": [
2306
+ "hellenic cooperative oncology group"
2307
+ ],
2308
+ "chin med j": [
2309
+ "engl"
2310
+ ],
2311
+ "engl": [
2312
+ "chin med j"
2313
+ ],
2314
+ "commun": [
2315
+ "lond"
2316
+ ],
2317
+ "lond": [
2318
+ "cancer commun",
2319
+ "commun"
2320
+ ],
2321
+ "mertinib": [
2322
+ "osi"
2323
+ ],
2324
+ "osi": [
2325
+ "mertinib"
2326
+ ],
2327
+ "platinum-pemetrexed in egfr-mutated": [
2328
+ "egfrm"
2329
+ ],
2330
+ "egfrm": [
2331
+ "with stage ibeiiia egfr mutation positive",
2332
+ "platinum-pemetrexed in egfr-mutated"
2333
+ ],
2334
+ "advanced non-small cell lung cancer": [
2335
+ "nsclc"
2336
+ ],
2337
+ "cancer commun": [
2338
+ "lond"
2339
+ ],
2340
+ "e-mutant metastatic nsclc": [
2341
+ "mnsclc"
2342
+ ],
2343
+ "mnsclc": [
2344
+ "e-mutant metastatic nsclc"
2345
+ ],
2346
+ "binimetinib in patients": [
2347
+ "pts"
2348
+ ],
2349
+ "pts": [
2350
+ "binimetinib in patients",
2351
+ "p repotrectinib in patients",
2352
+ "versus docetaxel in patients",
2353
+ "mo encorafenib plus\n\nbinimetinib in patients",
2354
+ "therapy in patients",
2355
+ "patients"
2356
+ ],
2357
+ "mutant advanced non-small cell lung cancer": [
2358
+ "nsclc"
2359
+ ],
2360
+ "patients": [
2361
+ "pts"
2362
+ ],
2363
+ "with epidermal growth factor receptor": [
2364
+ "egfr"
2365
+ ],
2366
+ "egfr": [
2367
+ "with epidermal growth factor receptor"
2368
+ ],
2369
+ "treatment of early stages": [
2370
+ "stages i-iiia",
2371
+ "stages i-ii"
2372
+ ],
2373
+ "stages i-iiia": [
2374
+ "treatment of early stages"
2375
+ ],
2376
+ "stages i-ii": [
2377
+ "treatment of early stages"
2378
+ ],
2379
+ "and the european medicines\nagency": [
2380
+ "ema"
2381
+ ],
2382
+ "chemotherapy": [
2383
+ "adaura",
2384
+ "cht"
2385
+ ],
2386
+ "the median\nwas not reached": [
2387
+ "ne-ne"
2388
+ ],
2389
+ "ne-ne": [
2390
+ "the median\nwas not reached"
2391
+ ],
2392
+ "neoadjuvant immune checkpoint inhibitors": [
2393
+ "icis"
2394
+ ],
2395
+ "leads to\nincreased dfs versus best supportive care": [
2396
+ "bsc"
2397
+ ],
2398
+ "the\nimmune strategy in the": [
2399
+ "neo"
2400
+ ],
2401
+ "or docetaxel or pemetrexed": [
2402
+ "only in\nadenocarcinoma tumours"
2403
+ ],
2404
+ "only in\nadenocarcinoma tumours": [
2405
+ "or docetaxel or pemetrexed"
2406
+ ],
2407
+ "post-operative radiotherapy": [
2408
+ "port"
2409
+ ],
2410
+ "port": [
2411
+ "post-operative radiotherapy"
2412
+ ],
2413
+ "treatment of locally advanced stage": [
2414
+ "stage iii"
2415
+ ],
2416
+ "negative endoscopic staging": [
2417
+ "ebus or eus"
2418
+ ],
2419
+ "ebus or eus": [
2420
+ "negative endoscopic staging"
2421
+ ],
2422
+ "of whom had undergone positron\nemission tomography": [
2423
+ "pet"
2424
+ ],
2425
+ "systemic treatment algorithm for early-stage": [
2426
+ "stage ib-iiia"
2427
+ ],
2428
+ "stage ib-iiia": [
2429
+ "systemic treatment algorithm for early-stage"
2430
+ ],
2431
+ "and unresectable locally advanced": [
2432
+ "stage iii"
2433
+ ],
2434
+ "general categories or stratification": [
2435
+ "symptom"
2436
+ ],
2437
+ "symptom": [
2438
+ "general categories or stratification"
2439
+ ],
2440
+ "and the food and drug administration": [
2441
+ "fda"
2442
+ ],
2443
+ "unresectable nsclc": [
2444
+ "stage iii"
2445
+ ],
2446
+ "concurrent chemoradiation therapy": [
2447
+ "pacific"
2448
+ ],
2449
+ "pacific": [
2450
+ "small-cell lung cancer",
2451
+ "concurrent chemoradiation therapy"
2452
+ ],
2453
+ "adaura": [
2454
+ "chemotherapy"
2455
+ ],
2456
+ "d approval was based on all patient data": [
2457
+ "including stage ib"
2458
+ ],
2459
+ "including stage ib": [
2460
+ "d approval was based on all patient data"
2461
+ ],
2462
+ "on tumour cells": [
2463
+ "as per the\nema-approved indication"
2464
+ ],
2465
+ "as per the\nema-approved indication": [
2466
+ "on tumour cells"
2467
+ ],
2468
+ "gico clara campal": [
2469
+ "hm-ciocc"
2470
+ ],
2471
+ "hm-ciocc": [
2472
+ "gico clara campal"
2473
+ ],
2474
+ "rolf stahel": [
2475
+ "esmo guidelines steering committee"
2476
+ ],
2477
+ "esmo guidelines steering committee": [
2478
+ "rolf stahel"
2479
+ ],
2480
+ "george pentheroudakis": [
2481
+ "chief medical officer of esmo"
2482
+ ],
2483
+ "chief medical officer of esmo": [
2484
+ "george pentheroudakis"
2485
+ ],
2486
+ "richard lutz and jennifer lamarre": [
2487
+ "esmo staff"
2488
+ ],
2489
+ "esmo staff": [
2490
+ "richard lutz and jennifer lamarre"
2491
+ ],
2492
+ "nicola latino": [
2493
+ "esmo scientific affairs staff"
2494
+ ],
2495
+ "research support as": [
2496
+ "sub"
2497
+ ],
2498
+ "with stage ibeiiia egfr mutation positive": [
2499
+ "egfrm"
2500
+ ],
2501
+ "nivolumab": [
2502
+ "bristol myers squibb statement on opdivo",
2503
+ "nivo"
2504
+ ],
2505
+ "nivo": [
2506
+ "nivolumab"
2507
+ ],
2508
+ "platinum-doublet\nchemotherapy": [
2509
+ "chemo"
2510
+ ],
2511
+ "chemo": [
2512
+ "platinum-based chemotherapy",
2513
+ "platinum-doublet\nchemotherapy"
2514
+ ],
2515
+ "for\nresectable": [
2516
+ "ib-iiia"
2517
+ ],
2518
+ "ib-iiia": [
2519
+ "for\nresectable"
2520
+ ],
2521
+ "lung cancer": [
2522
+ "nsclc"
2523
+ ],
2524
+ "iii non-small-cell lung cancer": [
2525
+ "nsclc"
2526
+ ],
2527
+ "products for human use": [
2528
+ "chmp"
2529
+ ],
2530
+ "of circulating tumor dna": [
2531
+ "ctdna"
2532
+ ],
2533
+ "ctdna": [
2534
+ "of circulating tumor dna"
2535
+ ],
2536
+ "diques august pi i sunyer": [
2537
+ "idibaps"
2538
+ ],
2539
+ "idibaps": [
2540
+ "diques august pi i sunyer"
2541
+ ],
2542
+ "department of radiation oncology": [
2543
+ "maastro clinic"
2544
+ ],
2545
+ "maastro clinic": [
2546
+ "department of radiation oncology"
2547
+ ],
2548
+ "and tumour mutational\nburden": [
2549
+ "tmb"
2550
+ ],
2551
+ "tmb": [
2552
+ "and tumour mutational\nburden"
2553
+ ],
2554
+ "staging and risk assessment\n\n\nthe tnm": [
2555
+ "tumourenodeemetastasis"
2556
+ ],
2557
+ "-deoxy-d-glucose positron\n\ne e\nemission tomography": [
2558
+ "fdg pet"
2559
+ ],
2560
+ "fdg pet": [
2561
+ "-deoxy-d-glucose positron\n\ne e\nemission tomography"
2562
+ ],
2563
+ "and\na magnetic resonance imaging": [
2564
+ "mri"
2565
+ ],
2566
+ "elevated lactate dehydrogenase": [
2567
+ "ldh"
2568
+ ],
2569
+ "ldh": [
2570
+ "elevated lactate dehydrogenase"
2571
+ ],
2572
+ "creatinine\nand lung function test": [
2573
+ "if localised disease"
2574
+ ],
2575
+ "if localised disease": [
2576
+ "creatinine\nand lung function test"
2577
+ ],
2578
+ "pet is available\nimaging of the brain": [
2579
+ "preferably mri"
2580
+ ],
2581
+ "preferably mri": [
2582
+ "pet is available\nimaging of the brain"
2583
+ ],
2584
+ "the use of granulocyte\ncolony-stimulating factor": [
2585
+ "g-csf"
2586
+ ],
2587
+ "g-csf": [
2588
+ "the use of granulocyte\ncolony-stimulating factor"
2589
+ ],
2590
+ "no\nimprovement in progression-free survival": [
2591
+ "pfs"
2592
+ ],
2593
+ "both given concurrently with cht": [
2594
+ "starting on cycle\ntwo"
2595
+ ],
2596
+ "starting on cycle\ntwo": [
2597
+ "both given concurrently with cht"
2598
+ ],
2599
+ "an historical southwest\n\noncology group": [
2600
+ "swog"
2601
+ ],
2602
+ "swog": [
2603
+ "an historical southwest\n\noncology group"
2604
+ ],
2605
+ "area under the curve": [
2606
+ "auc"
2607
+ ],
2608
+ "auc": [
2609
+ "area under the curve"
2610
+ ],
2611
+ "-year os": [
2612
+ "primary endpoint"
2613
+ ],
2614
+ "interval": [
2615
+ "tfi"
2616
+ ],
2617
+ "tfi": [
2618
+ "interval"
2619
+ ],
2620
+ "the\norr": [
2621
+ "primary outcome measure"
2622
+ ],
2623
+ "primary outcome measure": [
2624
+ "the\norr"
2625
+ ],
2626
+ "comparing\nnivolumab to topotecan": [
2627
+ "or amrubicin"
2628
+ ],
2629
+ "or amrubicin": [
2630
+ "comparing\nnivolumab to topotecan"
2631
+ ],
2632
+ "as second-line\ntreatment in unselected": [
2633
+ "platinum-sensitive and -resistant"
2634
+ ],
2635
+ "platinum-sensitive and -resistant": [
2636
+ "as second-line\ntreatment in unselected"
2637
+ ],
2638
+ "e\nrovalpituzumab tesirine": [
2639
+ "rova-t"
2640
+ ],
2641
+ "rova-t": [
2642
+ "e\nrovalpituzumab tesirine"
2643
+ ],
2644
+ "the preferred cht for patients with limited-stage": [
2645
+ "stage\ni-iii"
2646
+ ],
2647
+ "stage\ni-iii": [
2648
+ "the preferred cht for patients with limited-stage"
2649
+ ],
2650
+ "another reason for regular": [
2651
+ "long-term"
2652
+ ],
2653
+ "long-term": [
2654
+ "another reason for regular"
2655
+ ],
2656
+ "forthcoming": [
2657
+ "seventh"
2658
+ ],
2659
+ "seventh": [
2660
+ "forthcoming"
2661
+ ],
2662
+ "techniques": [
2663
+ "ct versus mri"
2664
+ ],
2665
+ "ct versus mri": [
2666
+ "techniques"
2667
+ ],
2668
+ "front med": [
2669
+ "lausanne"
2670
+ ],
2671
+ "lausanne": [
2672
+ "front med"
2673
+ ],
2674
+ "cell lung cancer": [
2675
+ "convert"
2676
+ ],
2677
+ "convert": [
2678
+ "cell lung cancer"
2679
+ ],
2680
+ "dose prophylactic cranial irradiation": [
2681
+ "pci"
2682
+ ],
2683
+ "extensive-stage small-cell lung cancer": [
2684
+ "caspian"
2685
+ ],
2686
+ "caspian": [
2687
+ "extensive-stage small-cell lung cancer",
2688
+ "cer"
2689
+ ],
2690
+ "cer": [
2691
+ "caspian"
2692
+ ],
2693
+ "plus ipilimumab": [
2694
+ "ipi"
2695
+ ],
2696
+ "ipi": [
2697
+ "plus ipilimumab"
2698
+ ],
2699
+ "or placebo": [
2700
+ "pbo"
2701
+ ],
2702
+ "pbo": [
2703
+ "or placebo"
2704
+ ],
2705
+ "therapy in patients": [
2706
+ "pts"
2707
+ ],
2708
+ "platinum-based chemotherapy": [
2709
+ "chemo"
2710
+ ],
2711
+ "bristol myers squibb statement on opdivo": [
2712
+ "nivolumab"
2713
+ ],
2714
+ "ukcccr": [
2715
+ "research"
2716
+ ],
2717
+ "and treatment of cancer": [
2718
+ "eortc"
2719
+ ],
2720
+ "eortc": [
2721
+ "and treatment of cancer"
2722
+ ],
2723
+ "randomized trial radiation therapy oncology group": [
2724
+ "rtog"
2725
+ ],
2726
+ "rtog": [
2727
+ "randomized trial radiation therapy oncology group"
2728
+ ],
2729
+ "a phase iii randomised clinical trial": [
2730
+ "rct"
2731
+ ],
2732
+ "tyrosine kinase inhibitor": [
2733
+ "tki"
2734
+ ],
2735
+ "oligoprogression\n\nlocal treatment": [
2736
+ "surgery or rt"
2737
+ ],
2738
+ "vascular endothelial growth factor": [
2739
+ "receptor"
2740
+ ],
2741
+ "receptor": [
2742
+ "vascular endothelial growth factor"
2743
+ ],
2744
+ "or food and drug administration": [
2745
+ "fda"
2746
+ ],
2747
+ "nicola\nlatino and francesca chiovaro": [
2748
+ "esmo scientific affairs staff"
2749
+ ],
2750
+ "esmo medical affairs staff": [
2751
+ "and dr svetlana jezdic"
2752
+ ],
2753
+ "the study of lung cancer": [
2754
+ "iaslc"
2755
+ ],
2756
+ "iaslc": [
2757
+ "the study of lung cancer"
2758
+ ],
2759
+ "global breast cancer initiative": [
2760
+ "gbci"
2761
+ ],
2762
+ "gbci": [
2763
+ "global breast cancer initiative"
2764
+ ],
2765
+ "european school of oncology": [
2766
+ "eso"
2767
+ ],
2768
+ "eso": [
2769
+ "european school of oncology"
2770
+ ],
2771
+ "and society for immunotherapy and cancer": [
2772
+ "sitc"
2773
+ ],
2774
+ "sitc": [
2775
+ "and society for immunotherapy and cancer"
2776
+ ],
2777
+ "p repotrectinib in patients": [
2778
+ "pts"
2779
+ ],
2780
+ "mo encorafenib plus\n\nbinimetinib in patients": [
2781
+ "pts"
2782
+ ],
2783
+ "versus docetaxel in patients": [
2784
+ "pts"
2785
+ ],
2786
+ "of molecular targets": [
2787
+ "escat"
2788
+ ],
2789
+ "escat": [
2790
+ "of molecular targets"
2791
+ ],
2792
+ "european society for medical oncology": [
2793
+ "esmo"
2794
+ ],
2795
+ "nice": [
2796
+ "national institute for health and care excellence",
2797
+ "nhs"
2798
+ ],
2799
+ "national institute for health and care excellence": [
2800
+ "nice"
2801
+ ],
2802
+ "world health organization": [
2803
+ "who"
2804
+ ],
2805
+ "australian national lung cancer screening program": [
2806
+ "nlcsp"
2807
+ ],
2808
+ "nlcsp": [
2809
+ "australian national lung cancer screening program"
2810
+ ],
2811
+ "- esmo": [
2812
+ "selected guidelines"
2813
+ ],
2814
+ "selected guidelines": [
2815
+ "- esmo"
2816
+ ],
2817
+ "- asco": [
2818
+ "stage iv guidelines"
2819
+ ],
2820
+ "stage iv guidelines": [
2821
+ "- asco"
2822
+ ],
2823
+ "low-dose ct": [
2824
+ "ldct"
2825
+ ],
2826
+ "nhs": [
2827
+ "nice"
2828
+ ],
2829
+ "vs insurance-based": [
2830
+ "nccn"
2831
+ ],
2832
+ "vs universal": [
2833
+ "who"
2834
+ ],
2835
+ "early": [
2836
+ "i-ii"
2837
+ ],
2838
+ "i-ii": [
2839
+ "early"
2840
+ ],
2841
+ "locally advanced": [
2842
+ "iii"
2843
+ ],
2844
+ "iii": [
2845
+ "locally advanced"
2846
+ ],
2847
+ "global": [
2848
+ "who"
2849
+ ],
2850
+ "- regular imaging": [
2851
+ "ct scans"
2852
+ ],
2853
+ "ct scans": [
2854
+ "- regular imaging"
2855
+ ],
2856
+ "- surgery": [
2857
+ "early stages"
2858
+ ],
2859
+ "early stages": [
2860
+ "- surgery"
2861
+ ],
2862
+ "- radiotherapy": [
2863
+ "radiation"
2864
+ ],
2865
+ "radiation": [
2866
+ "- radiotherapy"
2867
+ ],
2868
+ "global statistics": [
2869
+ "who"
2870
+ ]
2871
+ },
2872
+ "abbreviations": {
2873
+ "esmo": [
2874
+ "european society of medical oncology",
2875
+ "the most recent european society for medical oncology",
2876
+ "european society for medical oncology",
2877
+ "european\nsociety of medical oncology",
2878
+ "european society for\nmedical oncology",
2879
+ "the european society for medical oncology",
2880
+ "the following european society for medical oncology",
2881
+ "european society for medical\noncology"
2882
+ ],
2883
+ "asco": [
2884
+ "american\nsociety of clinical oncology",
2885
+ "american society of clinical\noncology",
2886
+ "american society of clinical\n\noncology",
2887
+ "american society of clinical oncology",
2888
+ "the clinical practice guidelines published herein are provided by the american society of clinical oncology inc",
2889
+ "this american society of clinical oncology"
2890
+ ],
2891
+ "aiom": [
2892
+ "italian association\nof medical oncology",
2893
+ "the italian association of medical oncology",
2894
+ "italian association of medical oncology"
2895
+ ],
2896
+ "nccn": [
2897
+ "national comprehensive cancer network",
2898
+ "american cancer centers"
2899
+ ],
2900
+ "glides": [
2901
+ "ecision support",
2902
+ "guidelines into decision\nsupport"
2903
+ ],
2904
+ "glc": [
2905
+ "guidelines committee"
2906
+ ],
2907
+ "mcbs": [
2908
+ "magnitude of clinical benefit scale",
2909
+ "magnitude\nof clinical benefit score"
2910
+ ],
2911
+ "ema": [
2912
+ "european medicines agency",
2913
+ "european medicines\nagency"
2914
+ ],
2915
+ "sclc": [
2916
+ "small cell lung cancer",
2917
+ "clinical practice guidelines on small cell lung\ncancer"
2918
+ ],
2919
+ "cco": [
2920
+ "cancer care ontario"
2921
+ ],
2922
+ "astro": [
2923
+ "executive summary of an american society for\nradiation oncology"
2924
+ ],
2925
+ "inst": [
2926
+ "calithera biosciences",
2927
+ "novartis",
2928
+ "cullinan oncology",
2929
+ "regeneron",
2930
+ "kline canada",
2931
+ "verastem",
2932
+ "genentech",
2933
+ "amgen",
2934
+ "bayer",
2935
+ "bristol myers squibb foundation",
2936
+ "puma biotechnology",
2937
+ "boehringer ingelheim",
2938
+ "genomics",
2939
+ "myers squibb",
2940
+ "arcus biosciences",
2941
+ "kline",
2942
+ "turning point therapeutics",
2943
+ "takeda",
2944
+ "revolution medicines",
2945
+ "merck serono",
2946
+ "zeneca",
2947
+ "macrogenics",
2948
+ "merck",
2949
+ "summit therapeutics",
2950
+ "palobiofarma",
2951
+ "astex pharmaceuticals",
2952
+ "zeneca canada",
2953
+ "black diamond\ntherapeutics",
2954
+ "janssen oncology",
2955
+ "mirati therapeutics",
2956
+ "bristol myers squibb",
2957
+ "dohme",
2958
+ "immune",
2959
+ "sutro biopharma",
2960
+ "polaris",
2961
+ "pfizer",
2962
+ "forward",
2963
+ "elevation oncology",
2964
+ "astra zeneca",
2965
+ "heart therapeutics",
2966
+ "nuvation bio",
2967
+ "inhibrx",
2968
+ "pharmaceuticals",
2969
+ "bristol myers\nsquibb",
2970
+ "roche",
2971
+ "dizal\npharma",
2972
+ "harpoon therapeutics",
2973
+ "vivace therapeutics",
2974
+ "janssen",
2975
+ "jazz pharmaceuticals",
2976
+ "advaxis",
2977
+ "lilly",
2978
+ "constellation pharmaceuticals",
2979
+ "guardant health",
2980
+ "trizell",
2981
+ "blueprint medicines",
2982
+ "therapeutics",
2983
+ "exelixis"
2984
+ ],
2985
+ "ct": [
2986
+ "clinicians should use a diagnostic chest computed tomography",
2987
+ "the use of\ncomputed tomography",
2988
+ "computed tomography"
2989
+ ],
2990
+ "mri": [
2991
+ "what is the role of brain magnetic resonance imaging"
2992
+ ],
2993
+ "sbrt": [
2994
+ "salvage stereotactic body radiation therapy",
2995
+ "stereotactic body radiotherapy"
2996
+ ],
2997
+ "cap": [
2998
+ "pathologists"
2999
+ ],
3000
+ "iaslc": [
3001
+ "international association for the\n\nstudy of lung cancer",
3002
+ "pathology committee chair\nfor international association for the study of lung cancer",
3003
+ "study of lung cancer",
3004
+ "international association for the\nstudy of lung cancer",
3005
+ "international association for\nthe study of lung cancer",
3006
+ "the\ninternational association for the study of lung cancer"
3007
+ ],
3008
+ "amp": [
3009
+ "association\nfor molecular pathology"
3010
+ ],
3011
+ "ihc": [
3012
+ "immunohistochemistry"
3013
+ ],
3014
+ "ctc": [
3015
+ "there is currently insufficient evidence to support the use of circulating tumor cell"
3016
+ ],
3017
+ "mars": [
3018
+ "although the results from the mesothelioma and radical surgery"
3019
+ ],
3020
+ "os": [
3021
+ "overall survival",
3022
+ "the median\noverall survival"
3023
+ ],
3024
+ "elsevier": [
3025
+ "clinical lung cancer"
3026
+ ],
3027
+ "rct": [
3028
+ "one randomized controlled trial"
3029
+ ],
3030
+ "ps": [
3031
+ "eastern cooperative oncology group performance\nstatus"
3032
+ ],
3033
+ "orr": [
3034
+ "reuss et al\n\n\n\nrate",
3035
+ "is result in a lower overall response\nrate"
3036
+ ],
3037
+ "pci": [
3038
+ "prophylactic cranial irradiation"
3039
+ ],
3040
+ "fda": [
3041
+ "osimertinib is approved by both the united states food and\ndrug administration",
3042
+ "these results led to the food\n\nand drug administration",
3043
+ "united states food and drug administration",
3044
+ "food and drug administration",
3045
+ "entrectinib received food and\ndrug administration"
3046
+ ],
3047
+ "crs": [
3048
+ "cytokine release syndrome"
3049
+ ],
3050
+ "ikv": [
3051
+ "department of surgical sciences"
3052
+ ],
3053
+ "who": [
3054
+ "global",
3055
+ "global statistics",
3056
+ "the latest world health organization",
3057
+ "world health organization",
3058
+ "the recent world health organization"
3059
+ ],
3060
+ "lc": [
3061
+ "these\nguidelines are restricted to lung carcinoid"
3062
+ ],
3063
+ "seer": [
3064
+ "epidemiology and end results",
3065
+ "end results"
3066
+ ],
3067
+ "uicc": [
3068
+ "union for international cancer control",
3069
+ "edition of the union for\ninternational cancer control",
3070
+ "union for\ninternational cancer control",
3071
+ "union for international\ncancer control"
3072
+ ],
3073
+ "gep": [
3074
+ "based on\napproval and recommendations in gastroenteropancreatic"
3075
+ ],
3076
+ "pth": [
3077
+ "annals of oncology\n\n\n\nparathyroid hormone"
3078
+ ],
3079
+ "rfa": [
3080
+ "for these patients radiofrequency ablation",
3081
+ "palliative surgery\nor radiofrequency ablation"
3082
+ ],
3083
+ "recist": [
3084
+ "measurements and response assessment should follow\nresponse evaluation criteria in solid tumours",
3085
+ "cs with response evaluation criteria\nin solid tumours",
3086
+ "measurements and response assessment should follow response evaluation criteria in solid tumours"
3087
+ ],
3088
+ "gemox": [
3089
+ "oxaliplatin combined with gemcitabine"
3090
+ ],
3091
+ "lan": [
3092
+ "lanreotide autogel"
3093
+ ],
3094
+ "chuv": [
3095
+ "centre hospitalier universitaire vaudois",
3096
+ "centre hospitalier universitaire\nvaudois"
3097
+ ],
3098
+ "nlst": [
3099
+ "national cancer institute\nannounced the results of the national lung cancer screening\ntrial",
3100
+ "the much larger national lung cancer screening trial"
3101
+ ],
3102
+ "bts": [
3103
+ "guidelines developed by the british thoracic society"
3104
+ ],
3105
+ "pet": [
3106
+ "the latter recommend a lesser reliance on positron emission tomography"
3107
+ ],
3108
+ "nice": [
3109
+ "national institute for health and care\nexcellence"
3110
+ ],
3111
+ "accp": [
3112
+ "american college of chest physicians"
3113
+ ],
3114
+ "rcri": [
3115
+ "evaluation of the cardiac risk assessment for lung resections\nby the recalibrated thoracic revised cardiac risk index"
3116
+ ],
3117
+ "lcsg": [
3118
+ "based on the lung cancer study group"
3119
+ ],
3120
+ "egfr": [
3121
+ "for cases with mutation in epidermal growth factor receptor"
3122
+ ],
3123
+ "rtog": [
3124
+ "radiation therapy oncology group",
3125
+ "data from a completed prospective\nradiation therapy oncology group"
3126
+ ],
3127
+ "esge": [
3128
+ "european society of gastrointestinal endoscopy"
3129
+ ],
3130
+ "ers": [
3131
+ "european respiratory society"
3132
+ ],
3133
+ "ests": [
3134
+ "european\nsociety of thoracic surgeons",
3135
+ "european society of thoracic surgeons"
3136
+ ],
3137
+ "thoracoscore": [
3138
+ "the thoracic surgery scoring\nsystem",
3139
+ "the thoracic surgery scoring system"
3140
+ ],
3141
+ "pulmonology": [
3142
+ "respiratory oncology",
3143
+ "respiratory oncology unit"
3144
+ ],
3145
+ "acs": [
3146
+ "lung cancer screening guidelines published by the\namerican cancer society"
3147
+ ],
3148
+ "ialt": [
3149
+ "some trials"
3150
+ ],
3151
+ "anita": [
3152
+ "adjuvant navelbine international trialist association"
3153
+ ],
3154
+ "sabr": [
3155
+ "radiographic changes after lung stereotactic\nablative radiotherapy"
3156
+ ],
3157
+ "vumc": [
3158
+ "vrije\nuniversity medical centre",
3159
+ "university medical centre"
3160
+ ],
3161
+ "ub": [
3162
+ "bemeneed"
3163
+ ],
3164
+ "bms": [
3165
+ "myers\nsquibb",
3166
+ "bristol myers squibb",
3167
+ "bristol myers\nsquibb",
3168
+ "bristol\nmyers squibb"
3169
+ ],
3170
+ "msd": [
3171
+ "dohme"
3172
+ ],
3173
+ "eortc": [
3174
+ "chair of the european\norganisation for research and treatment of cancer",
3175
+ "european\norganisation for research and treatment of cancer",
3176
+ "treatment of cancer"
3177
+ ],
3178
+ "cpg": [
3179
+ "clinical practice guideline"
3180
+ ],
3181
+ "escat": [
3182
+ "targets",
3183
+ "scale for clinical actionability of\nmolecular targets",
3184
+ "scale for clinical actionability of molecular targets"
3185
+ ],
3186
+ "alk": [
3187
+ "positive anaplastic lymphoma kinase"
3188
+ ],
3189
+ "ish": [
3190
+ "detection is reliable by\nin situ hybridisation"
3191
+ ],
3192
+ "cns": [
3193
+ "imaging of the central nervous system"
3194
+ ],
3195
+ "ajcc": [
3196
+ "american joint committee on cancer",
3197
+ "american joint\ncommittee on cancer"
3198
+ ],
3199
+ "vb": [
3200
+ "ch cl"
3201
+ ],
3202
+ "ae": [
3203
+ "serious adverse event"
3204
+ ],
3205
+ "ild": [
3206
+ "interstitial lung disease"
3207
+ ],
3208
+ "kras": [
3209
+ "the\nkirsten rat sarcoma virus"
3210
+ ],
3211
+ "lat": [
3212
+ "data regarding the role of local ablative therapy"
3213
+ ],
3214
+ "eano": [
3215
+ "oncology"
3216
+ ],
3217
+ "gsk": [
3218
+ "kline"
3219
+ ],
3220
+ "nvalt": [
3221
+ "nederlandse vereniging van artsen voor longziekten en tuberculose",
3222
+ "lung cancer group and past secretary and current\nchair of the nederlandse vereniging van artsen voor longziekten en tuberculose"
3223
+ ],
3224
+ "atorg": [
3225
+ "asian\nthoracic oncology research group"
3226
+ ],
3227
+ "clcrf": [
3228
+ "chinese lung\ncancer research foundation limited"
3229
+ ],
3230
+ "csco": [
3231
+ "chinese society of clinical oncology",
3232
+ "chinese\nsociety of clinical oncology",
3233
+ "china"
3234
+ ],
3235
+ "hkcf": [
3236
+ "hong kong cancer fund"
3237
+ ],
3238
+ "hkcts": [
3239
+ "hong kong cancer therapy society"
3240
+ ],
3241
+ "per": [
3242
+ "education resource"
3243
+ ],
3244
+ "prime": [
3245
+ "partnerships in international medical education"
3246
+ ],
3247
+ "rtp": [
3248
+ "research\nto practice"
3249
+ ],
3250
+ "samo": [
3251
+ "president of swiss\nacademy of multidisciplinary oncology"
3252
+ ],
3253
+ "sakk": [
3254
+ "research",
3255
+ "president of lung group for swiss group for clinical cancer\nresearch"
3256
+ ],
3257
+ "etop": [
3258
+ "european thoracic oncology platform"
3259
+ ],
3260
+ "ibcsg": [
3261
+ "international breast cancer study group"
3262
+ ],
3263
+ "aacr": [
3264
+ "partners member\nof american association of cancer research"
3265
+ ],
3266
+ "asmac": [
3267
+ "clinique"
3268
+ ],
3269
+ "basel": [
3270
+ "cancers"
3271
+ ],
3272
+ "chmp": [
3273
+ "summary of opinion",
3274
+ "products for human use"
3275
+ ],
3276
+ "paga": [
3277
+ "asian adapted"
3278
+ ],
3279
+ "ishmo": [
3280
+ "indonesian society\nof hematology and medical oncology",
3281
+ "indonesia"
3282
+ ],
3283
+ "jsmo": [
3284
+ "japan",
3285
+ "japanese society of medical oncology"
3286
+ ],
3287
+ "ksmo": [
3288
+ "korean society for medical oncology",
3289
+ "korea"
3290
+ ],
3291
+ "mos": [
3292
+ "malaysia",
3293
+ "malaysian oncological society"
3294
+ ],
3295
+ "psmo": [
3296
+ "philippine society of medical\noncology",
3297
+ "philippine society of\nmedical oncology",
3298
+ "philippines"
3299
+ ],
3300
+ "sso": [
3301
+ "singapore",
3302
+ "singapore society of\noncology"
3303
+ ],
3304
+ "tos": [
3305
+ "taiwan oncology society",
3306
+ "taiwan"
3307
+ ],
3308
+ "tsco": [
3309
+ "thai society of clinical oncology",
3310
+ "thailand"
3311
+ ],
3312
+ "ismpo": [
3313
+ "indian\nsociety of medical and paediatric oncology"
3314
+ ],
3315
+ "nsmpa": [
3316
+ "national medical products\nadministration"
3317
+ ],
3318
+ "nmpa": [
3319
+ "chinese national\nmedical products administration"
3320
+ ],
3321
+ "jkn": [
3322
+ "the jaminan kesehatan nasional"
3323
+ ],
3324
+ "fornas": [
3325
+ "national standard of\nmedication list",
3326
+ "na\ntional drug formulary"
3327
+ ],
3328
+ "pap": [
3329
+ "open\n\n\n\nprogram"
3330
+ ],
3331
+ "pdma": [
3332
+ "it may take\nfrom several months to years for the pharmaceuticals and\nmedical devices agency"
3333
+ ],
3334
+ "nhi": [
3335
+ "national health insurance"
3336
+ ],
3337
+ "torg": [
3338
+ "thoracic oncology research\ngroup"
3339
+ ],
3340
+ "wjog": [
3341
+ "west japan oncology group"
3342
+ ],
3343
+ "tsc": [
3344
+ "trial steering committee"
3345
+ ],
3346
+ "idmc": [
3347
+ "committee"
3348
+ ],
3349
+ "ukiog": [
3350
+ "ireland oesophagogastric group"
3351
+ ],
3352
+ "lond": [
3353
+ "cancer commun",
3354
+ "commun"
3355
+ ],
3356
+ "nivo": [
3357
+ "nivolumab"
3358
+ ],
3359
+ "pa": [
3360
+ "philadelphia"
3361
+ ],
3362
+ "idibaps": [
3363
+ "august pi i sunyer"
3364
+ ],
3365
+ "swog": [
3366
+ "an historical southwest\n\noncology group"
3367
+ ],
3368
+ "cr": [
3369
+ "patients with a complete response"
3370
+ ],
3371
+ "rova-t": [
3372
+ "rovalpituzumab tesirine"
3373
+ ],
3374
+ "lausanne": [
3375
+ "front med"
3376
+ ],
3377
+ "coordinating": [
3378
+ "united kingdom"
3379
+ ],
3380
+ "ukcccr": [
3381
+ "research"
3382
+ ],
3383
+ "icf": [
3384
+ "international cancer foundation"
3385
+ ],
3386
+ "gbci": [
3387
+ "global breast cancer initiative"
3388
+ ],
3389
+ "esco": [
3390
+ "college of the european school of oncology"
3391
+ ],
3392
+ "eso": [
3393
+ "european school of oncology"
3394
+ ],
3395
+ "sitc": [
3396
+ "society for immunotherapy and cancer"
3397
+ ],
3398
+ "actionability": [
3399
+ "scale for clinical"
3400
+ ],
3401
+ "disease": [
3402
+ "centers for"
3403
+ ],
3404
+ "nlcsp": [
3405
+ "australian national lung cancer screening program"
3406
+ ],
3407
+ "iii": [
3408
+ "locally advanced"
3409
+ ],
3410
+ "iv": [
3411
+ "advanced"
3412
+ ],
3413
+ "nsclc": [
3414
+ "small cell lung cancer"
3415
+ ],
3416
+ "uk": [
3417
+ "guidelines"
3418
+ ]
3419
+ }
3420
+ }
logs/app.log CHANGED
The diff for this file is too large to render. See raw diff
 
requirements.txt CHANGED
@@ -36,3 +36,7 @@ torch==2.2.2+cpu
36
  python-docx==1.1.2
37
  reportlab==4.2.5
38
 
 
 
 
 
 
36
  python-docx==1.1.2
37
  reportlab==4.2.5
38
 
39
+ # Authentication
40
+ python-multipart>=0.0.18
41
+ itsdangerous==2.2.0
42
+