| 2750 | # --------------------------------------------------------------------------- |
| 2751 | |
| 2752 | class UpdateChecker: |
| 2753 | def __init__(self, state_file: Path = None, seed_mode: bool = False): |
| 2754 | self.state_file = state_file or ROOT / "scripts" / ".update_state.json" |
| 2755 | self.state = self._load_state() |
| 2756 | self.seed_mode = seed_mode |
| 2757 | self.registry = VersionRegistry() |
| 2758 | self.db_comparator = DatabaseComparator(ROOT) |
| 2759 | session = requests.Session() |
| 2760 | session.headers.update({"User-Agent": "Mozilla/5.0 (docmcp-knowledge-bot/2.0)"}) |
| 2761 | self.http = HTTPChecker(session, self.state) |
| 2762 | self.rss = RSSChecker(session, self.state, seed_mode) |
| 2763 | self.vertex = VertexAISearchChecker( |
| 2764 | VERTEX_AI_PROJECT_ID, VERTEX_AI_SEARCH_APP_ID, |
| 2765 | VERTEX_AI_SEARCH_API_KEY, self.state, seed_mode, |
| 2766 | ) |
| 2767 | self.google = GoogleSearchChecker("", "", self.state, seed_mode) # DEPRECATED |
| 2768 | self.web_search_available = self.vertex.available |
| 2769 | self.openfda = OpenFDAChecker(FDA_API_KEY, self.state) |
| 2770 | self.ecfr = ECFRChecker(session, self.state) |
| 2771 | self.eurlex = EURLexChecker(session, self.state) |
| 2772 | self.mdcg_scraper = MDCGPageChecker(session, self.state, self.db_comparator) |
| 2773 | self.ec_latest = ECLatestUpdatesChecker(session, self.state) |
| 2774 | self.fda_safety = FDASafetyRecallChecker(FDA_API_KEY, self.state) |
| 2775 | self.fda_recall = FDARecallChecker(FDA_API_KEY, self.state) |
| 2776 | self.cdrh_news = CDRHNewsChecker(session, self.state) |
| 2777 | self.atom_feed = AtomFeedChecker(session, self.state, seed_mode) |
| 2778 | self.canada_recalls = CanadaRecallsChecker(session, self.state, seed_mode) |
| 2779 | self.pmda_whatsnew = PMDAWhatsNewChecker(session, self.state, seed_mode) |
| 2780 | self.pmda = PMDAChecker(session, self.state, seed_mode) |
| 2781 | self.pmda_recalls = PMDARecallsChecker(session, self.state, seed_mode) |
| 2782 | self.mfds = MFDSChecker(session, self.state, seed_mode) |
| 2783 | self.generic_page = GenericPageChecker(session, self.state) |
| 2784 | # Tier 2 checkers (Phase 3b) |
| 2785 | from tier2_checkers import (TGARSSChecker, SwissmedicChecker, SFDAChecker, |
| 2786 | ANVISAChecker, MedsafeChecker, |
| 2787 | HSAGuidanceChecker, HSAAnnouncementsChecker, |
| 2788 | COFEPRISChecker, ANMATChecker, |
| 2789 | TFDAOpenDataChecker) |
| 2790 | self.tga_rss = TGARSSChecker(session, self.state, seed_mode) |
| 2791 | self.swissmedic = SwissmedicChecker(session, self.state, seed_mode) |
| 2792 | self.sfda = SFDAChecker(session, self.state, seed_mode) |
| 2793 | self.anvisa = ANVISAChecker(session, self.state, seed_mode) |
| 2794 | self.medsafe = MedsafeChecker(session, self.state, seed_mode) |
| 2795 | self.hsa_guidance = HSAGuidanceChecker(session, self.state, seed_mode) |
| 2796 | self.hsa_announcements = HSAAnnouncementsChecker(session, self.state, seed_mode) |
| 2797 | self.cofepris = COFEPRISChecker(session, self.state, seed_mode) |
| 2798 | self.anmat = ANMATChecker(session, self.state, seed_mode) |
| 2799 | self.tfda = TFDAOpenDataChecker(session, self.state, seed_mode) |
| 2800 | self.llm = LLMVersionAnalyzer(LLM_API_KEY, LLM_BASE_URL, LLM_MODEL) |
| 2801 | print("INFO: Google Search deprecated - all sources use direct parsing.") |
| 2802 | if not self.llm.available: |
| 2803 | print(f"INFO: LLM analysis not configured - set LLM_API_KEY " |
| 2804 | f"(LLM_BASE_URL={LLM_BASE_URL}, LLM_MODEL={LLM_MODEL}).") |
| 2805 | |
| 2806 | def _load_state(self) -> dict: |
| 2807 | if self.state_file.exists(): |
| 2808 | try: |
| 2809 | with open(self.state_file, "r", encoding="utf-8") as f: |