cdss-backend / evidenceScanner /src /web_scraper.py
shak3008's picture
Deploy CDSS Multi-Agent Biomedical System
82d7112
Raw History Blame Contribute Delete
4 kB
"""
web_scraper.py - Tavily REST Client for Clinical Practice Guidelines & Treatment Protocols.
Handles acute presentations with chronic risk factors (e.g., CKD dosing, Diabetes complications).
"""
import os
import requests
from typing import Dict, Any, Optional, List
from dotenv import load_dotenv
from tenacity import retry, stop_after_attempt, wait_exponential
load_dotenv()
TAVILY_API_KEY = os.getenv("TAVILY_API_KEY", "")
EXCLUDED_DOMAINS = [
"wikipedia.org", "youtube.com", "facebook.com", "twitter.com",
"reddit.com", "quora.com", "amazon.com", "pinterest.com"
]
class WebScraper:
def __init__(self, timeout: int = 10):
self.timeout = timeout
self.api_url = "https://api.tavily.com/search"
@retry(
stop=stop_after_attempt(2),
wait=wait_exponential(multiplier=1, min=2, max=4),
retry_error_callback=lambda retry_state: None
)
def crawl_and_extract(
self,
start_url: str = "",
topic: str = "",
chronic_risks: Optional[List[str]] = None
) -> Optional[Dict[str, Any]]:
"""
Executes Tavily search targeting treatment protocols, drug adjustments, and guidelines.
Accepts topic and optional chronic_risks list.
"""
if not TAVILY_API_KEY:
print("[WebScraper Warning] TAVILY_API_KEY is not configured in .env.")
return None
# Build query incorporating chronic comorbidity risk factors if present
if chronic_risks:
risk_context = " | ".join(chronic_risks)
search_query = (
f"{topic} | Clinical Practice Guidelines & Safe Treatments. "
f"Comorbidity Risk Measures: {risk_context}. "
f"Address drug dosing adjustments, treatment contraindications, and infection management."
)
else:
search_query = f"{topic} clinical practice guidelines management and treatment recommendations"
payload = {
"api_key": TAVILY_API_KEY,
"query": search_query,
"search_depth": "advanced",
"include_answer": "advanced",
"topic": "general",
"max_results": 3,
"exclude_domains": EXCLUDED_DOMAINS
}
try:
resp = requests.post(self.api_url, json=payload, timeout=self.timeout)
if resp.status_code != 200:
err_msg = f"[WebScraper Error] Tavily returned status {resp.status_code}: {resp.text}"
print(err_msg)
raise requests.HTTPError(err_msg)
data = resp.json()
ai_answer = data.get("answer", "").strip()
results = data.get("results", [])
# Primary reference details
primary_url = results[0].get("url", "https://tavily.com") if results else "https://tavily.com"
primary_title = results[0].get("title", f"{topic} Guidelines") if results else "Tavily Clinical Guidelines"
# Prefer the Tavily synthesized answer; fallback to top result snippet
combined_summary = ai_answer
if not combined_summary and results:
combined_summary = results[0].get("content", "").strip()
if not combined_summary:
return None
words = combined_summary.split()
if len(words) > 350:
combined_summary = " ".join(words[:350]) + "... [truncated]"
return {
"source": "Tavily Guidelines & Treatment Safety",
"url": primary_url,
"title": primary_title,
"abstract": combined_summary,
"extracted_text": combined_summary,
"query_matched": search_query,
"chronic_risk_adjusted": bool(chronic_risks),
"success": True
}
except Exception as e:
print(f"[WebScraper Error] Failed to execute Tavily query: {e}")
raise e