Spaces:
Running
Running
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 +5 -1
- .gitignore +1 -1
- 0.0.18 +2 -0
- api/__pycache__/app.cpython-313.pyc +0 -0
- api/__pycache__/middleware.cpython-313.pyc +0 -0
- api/app.py +4 -1
- api/middleware.py +49 -2
- api/routers/__pycache__/medical.cpython-313.pyc +0 -0
- api/routers/auth.py +174 -0
- core/__pycache__/agent.cpython-313.pyc +0 -0
- core/__pycache__/background_init.cpython-313.pyc +0 -0
- core/__pycache__/github_storage.cpython-313.pyc +0 -0
- core/__pycache__/retrievers.cpython-313.pyc +0 -0
- core/__pycache__/tools.cpython-313.pyc +0 -0
- core/__pycache__/validation.cpython-313.pyc +0 -0
- core/agent.py +71 -34
- core/background_init.py +18 -2
- core/context_enrichment.py +336 -0
- core/github_storage.py +14 -24
- core/medical_terminology.py +506 -0
- core/query_expansion.py +432 -0
- core/retrievers.py +103 -18
- core/tools.py +47 -14
- core/validation.py +18 -4
- data/medical_terms_cache.json +3420 -0
- logs/app.log +0 -0
- requirements.txt +4 -0
.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
|
| 93 |
-
Your primary purpose is to
|
| 94 |
-
|
| 95 |
-
Your
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
-
|
| 100 |
-
-
|
| 101 |
-
-
|
| 102 |
-
-
|
| 103 |
-
-
|
| 104 |
-
-
|
| 105 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 106 |
* Source file name
|
| 107 |
-
* Page number
|
| 108 |
-
* Provider name
|
| 109 |
-
* Specific location (e.g., Table 1, Figure 2,
|
| 110 |
-
* Type of content (e.g.,
|
| 111 |
-
|
| 112 |
-
|
|
|
|
| 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
|
| 117 |
-
* Describe which
|
| 118 |
-
* Reference any relevant footnotes or
|
|
|
|
| 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 |
-
-
|
| 124 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
-
-
|
|
|
|
|
|
|
| 131 |
- Always respond in English.
|
| 132 |
|
| 133 |
-
**FORMATTING:**
|
| 134 |
-
- Use markdown formatting for clarity:
|
| 135 |
-
* Use
|
| 136 |
-
* Use
|
| 137 |
-
* Use tables
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|
| 55 |
-
self._update_progress("
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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 |
-
#
|
| 230 |
-
|
| 231 |
-
|
| 232 |
-
|
| 233 |
-
|
| 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 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 =
|
| 110 |
-
"""Search FAISS vector store with optional provider metadata filter."""
|
| 111 |
_ensure_initialized()
|
| 112 |
if not _vector_store:
|
| 113 |
return []
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
try:
|
| 115 |
-
|
| 116 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
else:
|
| 118 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 =
|
| 130 |
-
"""Search BM25 using the global retriever
|
| 131 |
_ensure_initialized()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 132 |
try:
|
| 133 |
if not _bm25_retriever:
|
| 134 |
return []
|
| 135 |
-
|
| 136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 =
|
| 146 |
-
"""Combine vector and BM25 results (provider-filtered if provided)."""
|
| 147 |
_ensure_initialized() # Ensure retrievers are initialized before parallel execution
|
| 148 |
-
|
| 149 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
|
| 151 |
v_docs = f_vector.result()
|
| 152 |
b_docs = f_bm25.result()
|
| 153 |
-
# Merge uniquely by
|
| 154 |
seen = set()
|
| 155 |
merged = []
|
| 156 |
for d in v_docs + b_docs:
|
| 157 |
-
|
| 158 |
-
if
|
| 159 |
-
seen.add(
|
| 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 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 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
|
|
|
|
| 176 |
If provider is provided (e.g., "NCCN", "ASCO", "ESMO", "NICE"), results will be filtered by metadata provider.
|
| 177 |
-
|
| 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 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 190 |
_last_documents = []
|
| 191 |
-
for doc in
|
| 192 |
doc_dict = {
|
| 193 |
-
"doc_id": getattr(doc, 'id',
|
| 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 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 199 |
"content": doc.page_content
|
| 200 |
}
|
| 201 |
_last_documents.append(doc_dict)
|
| 202 |
|
| 203 |
-
return _format_docs_with_citations(
|
| 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
|
| 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 |
-
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
| 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 |
-
|
|
|
|
|
|
|
| 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 |
+
|