Spaces:
Sleeping
Sleeping
Download services.py from EnvironmentalAI/WNP-ARAG: direct link, hf CLI and curl.
- Browser
- Download file 26 kB
-
https://huggingface.co/spaces/EnvironmentalAI/WNP-ARAG/resolve/main/services.py
- Command line
-
hf download hf://spaces/EnvironmentalAI/WNP-ARAG/services.py
-
curl -L -o services.py https://huggingface.co/spaces/EnvironmentalAI/WNP-ARAG/resolve/main/services.py
26 kB
| import ast | |
| import json | |
| import logging | |
| import os | |
| import re | |
| import threading | |
| import time | |
| from pathlib import Path | |
| from typing import Any | |
| import unsloth | |
| import torch | |
| from langchain_community.embeddings import HuggingFaceEmbeddings | |
| from langchain_community.vectorstores import FAISS | |
| from unsloth import FastLanguageModel | |
| from config import ( | |
| EMBEDDING_MODEL_NAME, | |
| HF_TOKEN, | |
| JURISDICTIONS, | |
| LLM_MODEL_NAME, | |
| LOAD_IN_4BIT, | |
| MAX_ACCUMULATED_CHUNKS, | |
| MAX_CONTEXT_CHARACTERS, | |
| MAX_SEMANTIC_QUERY_CHARACTERS, | |
| MAX_SEMANTIC_QUERY_WORDS, | |
| MAX_SEQ_LENGTH, | |
| MODEL_DTYPE, | |
| jurisdiction_db_path, | |
| jurisdiction_name, | |
| normalize_jurisdiction, | |
| ) | |
| logger = logging.getLogger(__name__) | |
| _model = None | |
| _tokenizer = None | |
| _embeddings = None | |
| _vector_dbs: dict[str, FAISS] = {} | |
| _model_lock = threading.Lock() | |
| _embedding_lock = threading.Lock() | |
| _vector_lock = threading.Lock() | |
| _generation_lock = threading.Lock() | |
| _counter_lock = threading.Lock() | |
| _app_started_at = time.time() | |
| _requests_started = 0 | |
| _requests_completed = 0 | |
| _requests_failed = 0 | |
| def record_request_started() -> int: | |
| global _requests_started | |
| with _counter_lock: | |
| _requests_started += 1 | |
| return _requests_started | |
| def record_request_finished(success: bool) -> None: | |
| global _requests_completed, _requests_failed | |
| with _counter_lock: | |
| if success: | |
| _requests_completed += 1 | |
| else: | |
| _requests_failed += 1 | |
| def is_model_loaded() -> bool: | |
| return _model is not None and _tokenizer is not None | |
| def loaded_vector_db_codes() -> list[str]: | |
| with _vector_lock: | |
| return sorted(_vector_dbs.keys()) | |
| def is_vector_db_loaded(jurisdiction: str | None = None) -> bool: | |
| if jurisdiction is None: | |
| return bool(loaded_vector_db_codes()) | |
| code = normalize_jurisdiction(jurisdiction) | |
| with _vector_lock: | |
| return code in _vector_dbs | |
| def database_files_ready(jurisdiction: str) -> bool: | |
| db_path = jurisdiction_db_path(jurisdiction) | |
| return ( | |
| (db_path / "index.faiss").is_file() | |
| and (db_path / "index.pkl").is_file() | |
| ) | |
| def initialize_llm(): | |
| global _model, _tokenizer | |
| if is_model_loaded(): | |
| return _model, _tokenizer | |
| with _model_lock: | |
| if is_model_loaded(): | |
| return _model, _tokenizer | |
| if not torch.cuda.is_available(): | |
| raise RuntimeError( | |
| "CUDA is unavailable. This Space requires an NVIDIA GPU." | |
| ) | |
| kwargs = { | |
| "model_name": LLM_MODEL_NAME, | |
| "max_seq_length": MAX_SEQ_LENGTH, | |
| "dtype": MODEL_DTYPE, | |
| "load_in_4bit": LOAD_IN_4BIT, | |
| } | |
| if HF_TOKEN: | |
| kwargs["token"] = HF_TOKEN | |
| logger.info("Loading model: %s", LLM_MODEL_NAME) | |
| _model, _tokenizer = FastLanguageModel.from_pretrained(**kwargs) | |
| FastLanguageModel.for_inference(_model) | |
| _model.eval() | |
| if _tokenizer.pad_token_id is None: | |
| _tokenizer.pad_token = _tokenizer.eos_token | |
| logger.info("Model loaded.") | |
| return _model, _tokenizer | |
| def initialize_embeddings(): | |
| global _embeddings | |
| if _embeddings is not None: | |
| return _embeddings | |
| with _embedding_lock: | |
| if _embeddings is None: | |
| logger.info("Loading embedding model: %s", EMBEDDING_MODEL_NAME) | |
| _embeddings = HuggingFaceEmbeddings( | |
| model_name=EMBEDDING_MODEL_NAME | |
| ) | |
| return _embeddings | |
| def initialize_vector_db(jurisdiction: str): | |
| code = normalize_jurisdiction(jurisdiction) | |
| with _vector_lock: | |
| if code in _vector_dbs: | |
| return _vector_dbs[code] | |
| db_path = jurisdiction_db_path(code) | |
| if not database_files_ready(code): | |
| raise FileNotFoundError( | |
| f"The {jurisdiction_name(code)} FAISS database is incomplete. " | |
| f"Expected '{db_path / 'index.faiss'}' and " | |
| f"'{db_path / 'index.pkl'}'." | |
| ) | |
| embeddings = initialize_embeddings() | |
| logger.info( | |
| "Loading %s FAISS database: %s", | |
| jurisdiction_name(code), | |
| db_path, | |
| ) | |
| vector_db = FAISS.load_local( | |
| str(db_path), | |
| embeddings=embeddings, | |
| allow_dangerous_deserialization=True, | |
| ) | |
| _vector_dbs[code] = vector_db | |
| logger.info("%s FAISS database loaded.", jurisdiction_name(code)) | |
| return vector_db | |
| def call_llm(prompt: str, max_new_tokens: int) -> str: | |
| model, tokenizer = initialize_llm() | |
| chat = tokenizer.apply_chat_template( | |
| [{"role": "user", "content": prompt}], | |
| tokenize=False, | |
| add_generation_prompt=True, | |
| ) | |
| inputs = tokenizer( | |
| chat, | |
| return_tensors="pt", | |
| truncation=True, | |
| max_length=max(256, MAX_SEQ_LENGTH - max_new_tokens), | |
| ) | |
| device = next(model.parameters()).device | |
| inputs = {name: tensor.to(device) for name, tensor in inputs.items()} | |
| input_length = inputs["input_ids"].shape[-1] | |
| with _generation_lock, torch.inference_mode(): | |
| output = model.generate( | |
| **inputs, | |
| max_new_tokens=max_new_tokens, | |
| do_sample=False, | |
| use_cache=True, | |
| pad_token_id=tokenizer.pad_token_id, | |
| eos_token_id=tokenizer.eos_token_id, | |
| ) | |
| return tokenizer.decode( | |
| output[0, input_length:], | |
| skip_special_tokens=True, | |
| ).strip() | |
| def normalize_metadata(metadata: dict | None) -> dict: | |
| metadata = dict(metadata or {}) | |
| source = str(metadata.get("source") or "Unknown source") | |
| page = metadata.get("page") | |
| if page in (None, "", 0, "0"): | |
| page = "Unavailable" | |
| page_reference_basis = str( | |
| metadata.get("page_reference_basis") or "" | |
| ).strip() | |
| page_label = str( | |
| metadata.get("page_label") or "" | |
| ).strip() | |
| if not page_label: | |
| if str(page).lower() in { | |
| "unavailable", | |
| "unknown", | |
| "none", | |
| "null", | |
| "", | |
| }: | |
| page_label = "Page unavailable" | |
| elif page_reference_basis == "normalized_pdf": | |
| page_label = f"Page {page} (normalized PDF)" | |
| else: | |
| page_label = f"Page {page}" | |
| return { | |
| "title": str( | |
| metadata.get("title") | |
| or Path(source).stem.replace("_", " ").strip() | |
| or "Untitled document" | |
| ), | |
| "source": source, | |
| "url": str(metadata.get("url") or "").strip(), | |
| "page": page, | |
| "page_label": page_label, | |
| "page_reference_basis": page_reference_basis, | |
| "start_index": metadata.get("start_index"), | |
| "original_extension": str( | |
| metadata.get("original_extension") | |
| or Path(source).suffix.lower() | |
| ), | |
| "processing_extension": str( | |
| metadata.get("processing_extension") or "" | |
| ), | |
| "document_type": str( | |
| metadata.get("document_type") or "" | |
| ), | |
| } | |
| def retrieve_documents( | |
| query: str, | |
| top_k: int, | |
| jurisdiction: str, | |
| ) -> list[dict]: | |
| code = normalize_jurisdiction(jurisdiction) | |
| results = initialize_vector_db(code).similarity_search_with_score( | |
| query, | |
| k=top_k, | |
| ) | |
| chunks = [] | |
| for document, score in results: | |
| text = str(document.page_content or "").strip() | |
| if text: | |
| chunks.append( | |
| { | |
| "text": text, | |
| "metadata": normalize_metadata(document.metadata), | |
| "score": float(score), | |
| "jurisdiction": code, | |
| } | |
| ) | |
| return chunks | |
| def chunk_key(chunk: dict) -> tuple[str, str, str, str, str]: | |
| metadata = chunk["metadata"] | |
| return ( | |
| str(chunk.get("jurisdiction", "")), | |
| str(metadata.get("source", "")), | |
| str(metadata.get("page", "")), | |
| str(metadata.get("start_index", "")), | |
| chunk["text"].strip(), | |
| ) | |
| def add_unique_chunks( | |
| accumulated: list[dict], | |
| new_chunks: list[dict], | |
| seen: set, | |
| ) -> int: | |
| added = 0 | |
| for chunk in new_chunks: | |
| key = chunk_key(chunk) | |
| if key in seen: | |
| continue | |
| seen.add(key) | |
| accumulated.append(chunk) | |
| added += 1 | |
| if len(accumulated) >= MAX_ACCUMULATED_CHUNKS: | |
| break | |
| return added | |
| def page_display(metadata: dict) -> str: | |
| """Return the final human-readable page label.""" | |
| page_label = str( | |
| metadata.get("page_label") or "" | |
| ).strip() | |
| if page_label: | |
| return page_label | |
| page = metadata.get("page") | |
| if page in (None, "", 0, "0"): | |
| return "Page unavailable" | |
| if str(metadata.get("page_reference_basis") or "") == "normalized_pdf": | |
| return f"Page {page} (normalized PDF)" | |
| return f"Page {page}" | |
| def build_context(chunks: list[dict]) -> str: | |
| sections = [] | |
| used = 0 | |
| for number, chunk in enumerate(chunks, 1): | |
| metadata = chunk["metadata"] | |
| jurisdiction_code = str(chunk.get("jurisdiction", "")) | |
| jurisdiction_label = ( | |
| jurisdiction_name(jurisdiction_code) | |
| if jurisdiction_code in JURISDICTIONS | |
| else "" | |
| ) | |
| document_name = str( | |
| chunk.get("collection_label") | |
| or metadata.get("title") | |
| or Path(str(metadata.get("source") or "")).stem.replace("_", " ").strip() | |
| or "Uploaded document" | |
| ) | |
| metadata_lines = [ | |
| f"[Source {number}]", | |
| f"Document: {document_name}", | |
| f"Title: {metadata['title']}", | |
| f"Location: {page_display(metadata)}", | |
| ] | |
| if jurisdiction_label: | |
| metadata_lines.append(f"Jurisdiction: {jurisdiction_label}") | |
| section = ( | |
| "\n".join(metadata_lines) | |
| + "\nRetrieved text:\n" | |
| + chunk["text"] | |
| ) | |
| if sections and used + len(section) > MAX_CONTEXT_CHARACTERS: | |
| break | |
| sections.append(section) | |
| used += len(section) | |
| return "\n\n".join(sections) | |
| def format_sources(chunks: list[dict]) -> str: | |
| """Return predictable Markdown that the public frontend can parse.""" | |
| if not chunks: | |
| return "No source passages were retrieved." | |
| cards = [] | |
| for number, chunk in enumerate(chunks, 1): | |
| metadata = chunk["metadata"] | |
| preview = chunk["text"].strip() | |
| if len(preview) > 1200: | |
| preview = preview[:1200].rstrip() + "β¦" | |
| jurisdiction_code = str(chunk.get("jurisdiction", "")) | |
| jurisdiction_label = ( | |
| jurisdiction_name(jurisdiction_code) | |
| if jurisdiction_code in JURISDICTIONS | |
| else "" | |
| ) | |
| document_name = str( | |
| chunk.get("collection_label") | |
| or metadata.get("title") | |
| or Path(str(metadata.get("source") or "")).stem.replace("_", " ").strip() | |
| or "Uploaded document" | |
| ) | |
| title = str(metadata.get("title") or Path(document_name).name) | |
| metadata_parts = [ | |
| f"**Source:** {number}", | |
| f"**Page:** {page_display(metadata)}", | |
| f"**Document:** `{document_name}`", | |
| f"**Retrieval distance:** {chunk['score']:.4f}", | |
| ] | |
| if jurisdiction_label: | |
| metadata_parts.insert( | |
| 2, | |
| f"**Jurisdiction:** {jurisdiction_label}", | |
| ) | |
| url = str(metadata.get("url") or "").strip() | |
| if url: | |
| metadata_parts.append(f"**URL:** `{url}`") | |
| cards.append( | |
| f"### [{number}] {title}\n" | |
| + " | ".join(metadata_parts) | |
| + "\n\n" | |
| + preview | |
| ) | |
| return "\n\n---\n\n".join(cards) | |
| def normalize_source_citations( | |
| answer: str, | |
| source_count: int, | |
| ) -> str: | |
| """Keep answer citations aligned with the visible source cards.""" | |
| text = str(answer or "") | |
| if source_count < 1: | |
| return re.sub(r"\[[0-9,\s-]+\]", "", text) | |
| def replace(match: re.Match) -> str: | |
| raw = match.group(1).strip() | |
| if "," in raw or " " in raw: | |
| values = [int(value) for value in re.findall(r"\d+", raw)] | |
| valid = [ | |
| value for value in values | |
| if 1 <= value <= source_count | |
| ] | |
| return "".join(f"[{value}]" for value in valid) | |
| try: | |
| number = int(raw) | |
| except ValueError: | |
| return "" | |
| if 1 <= number <= source_count: | |
| return f"[{number}]" | |
| digits = [int(char) for char in raw if char.isdigit()] | |
| if ( | |
| len(digits) > 1 | |
| and all(1 <= value <= source_count for value in digits) | |
| ): | |
| return "".join(f"[{value}]" for value in digits) | |
| return "" | |
| text = re.sub(r"\[([0-9,\s]+)\]", replace, text) | |
| return re.sub(r"[ \t]{2,}", " ", text).strip() | |
| def compact_semantic_query(text: str) -> str: | |
| """Normalize and cap a semantic-search query without domain hard-coding.""" | |
| query = re.sub(r"\s+", " ", str(text or "")).strip().strip("\"'") | |
| query = re.sub(r"\b(?:SELECT|FROM|WHERE)\b", " ", query, flags=re.IGNORECASE) | |
| query = re.sub(r"\s+", " ", query).strip(" ,;|") | |
| words = query.split() | |
| if len(words) > MAX_SEMANTIC_QUERY_WORDS: | |
| query = " ".join(words[:MAX_SEMANTIC_QUERY_WORDS]) | |
| if len(query) > MAX_SEMANTIC_QUERY_CHARACTERS: | |
| query = query[:MAX_SEMANTIC_QUERY_CHARACTERS].rsplit(" ", 1)[0] | |
| return query.strip() | |
| def clean_search_query(text: str) -> str: | |
| query = re.sub( | |
| r"^```.*?\n|\n```$", | |
| "", | |
| str(text or "").strip(), | |
| flags=re.DOTALL, | |
| ) | |
| return compact_semantic_query(query) | |
| def _extract_balanced_json_object(text: str) -> str | None: | |
| start = text.find("{") | |
| if start < 0: | |
| return None | |
| depth = 0 | |
| in_string = False | |
| escaped = False | |
| for index in range(start, len(text)): | |
| char = text[index] | |
| if in_string: | |
| if escaped: | |
| escaped = False | |
| elif char == "\\": | |
| escaped = True | |
| elif char == '"': | |
| in_string = False | |
| continue | |
| if char == '"': | |
| in_string = True | |
| elif char == "{": | |
| depth += 1 | |
| elif char == "}": | |
| depth -= 1 | |
| if depth == 0: | |
| return text[start:index + 1] | |
| return None | |
| def _fallback_judgment_fields(text: str) -> dict: | |
| result: dict[str, Any] = {} | |
| boolean = re.search( | |
| r'["\']?sufficient["\']?\s*[:=]\s*(true|false|yes|no)', | |
| text, | |
| flags=re.IGNORECASE, | |
| ) | |
| if boolean: | |
| result["sufficient"] = boolean.group(1).lower() in {"true", "yes"} | |
| for key in ("missing_information", "reason", "next_search_focus"): | |
| match = re.search( | |
| rf'["\']?{key}["\']?\s*[:=]\s*["\']?(.*?)(?=\n\s*["\']?(?:sufficient|missing_information|reason|next_search_focus|cross_references)["\']?\s*[:=]|$)', | |
| text, | |
| flags=re.IGNORECASE | re.DOTALL, | |
| ) | |
| if match: | |
| result[key] = match.group(1).strip().strip('"\' ,') | |
| refs = re.search( | |
| r'["\']?cross_references["\']?\s*[:=]\s*(\[[^\]]*\]|[^\n]+)', | |
| text, | |
| flags=re.IGNORECASE, | |
| ) | |
| if refs: | |
| result["cross_references"] = normalize_regulatory_references(refs.group(1)) | |
| return result | |
| def parse_judgment(text: str) -> dict: | |
| """Parse structured model output with tolerant, deterministic fallbacks.""" | |
| cleaned = re.sub( | |
| r"```(?:json)?|```", | |
| "", | |
| str(text or ""), | |
| flags=re.IGNORECASE, | |
| ).strip() | |
| candidates = [cleaned] | |
| balanced = _extract_balanced_json_object(cleaned) | |
| if balanced and balanced != cleaned: | |
| candidates.append(balanced) | |
| for candidate in candidates: | |
| try: | |
| value = json.loads(candidate) | |
| if isinstance(value, dict): | |
| return value | |
| except (json.JSONDecodeError, TypeError): | |
| pass | |
| try: | |
| pythonish = re.sub(r"\btrue\b", "True", candidate, flags=re.IGNORECASE) | |
| pythonish = re.sub(r"\bfalse\b", "False", pythonish, flags=re.IGNORECASE) | |
| pythonish = re.sub(r"\bnull\b", "None", pythonish, flags=re.IGNORECASE) | |
| value = ast.literal_eval(pythonish) | |
| if isinstance(value, dict): | |
| return value | |
| except (ValueError, SyntaxError): | |
| pass | |
| fallback = _fallback_judgment_fields(cleaned) | |
| if "sufficient" in fallback: | |
| return fallback | |
| raise ValueError("No usable judgment object was found.") | |
| _FULL_RULE_REFERENCE = re.compile( | |
| r"\b\d{1,3}[A-Za-z]?[-β]\d{1,3}(?:\.\d+)+(?:\([A-Za-z0-9]+\))*(?=\W|$)", | |
| re.IGNORECASE, | |
| ) | |
| _STATUTE_REFERENCE = re.compile( | |
| r"(?<![-\d])\b\d{3}\.\d+(?:\([A-Za-z0-9]+\))*(?=\W|$)", | |
| re.IGNORECASE, | |
| ) | |
| _TABLE_APPENDIX_REFERENCE = re.compile( | |
| r"\b(?:Table|Appendix)\s+[A-Za-z0-9.-]+\b", | |
| re.IGNORECASE, | |
| ) | |
| def canonicalize_regulatory_reference(value: str) -> str: | |
| text = re.sub(r"\s+", " ", str(value or "")).strip(" .,;:\"'") | |
| text = re.sub( | |
| r"^(?:Rule|Chapter|section|subsection|paragraph|subparagraph)\s+", | |
| "", | |
| text, | |
| flags=re.IGNORECASE, | |
| ) | |
| text = text.replace("β", "-") | |
| full = _FULL_RULE_REFERENCE.search(text) | |
| if full: | |
| return full.group(0) | |
| table = _TABLE_APPENDIX_REFERENCE.search(text) | |
| if table: | |
| prefix, suffix = table.group(0).split(" ", 1) | |
| return f"{prefix.title()} {suffix}" | |
| statute = _STATUTE_REFERENCE.search(text) | |
| if statute: | |
| return statute.group(0) | |
| return "" | |
| def normalize_regulatory_references(value: Any, limit: int = 12) -> list[str]: | |
| """Return unique canonical citations and exclude paths or prose.""" | |
| if value is None: | |
| return [] | |
| if isinstance(value, (list, tuple, set)): | |
| raw_items = [str(item or "") for item in value] | |
| else: | |
| raw_items = [str(value or "")] | |
| candidates: list[str] = [] | |
| for raw in raw_items: | |
| candidates.extend(match.group(0) for match in _FULL_RULE_REFERENCE.finditer(raw)) | |
| candidates.extend(match.group(0) for match in _TABLE_APPENDIX_REFERENCE.finditer(raw)) | |
| occupied = [match.span() for match in _FULL_RULE_REFERENCE.finditer(raw)] | |
| for match in _STATUTE_REFERENCE.finditer(raw): | |
| if not any(start <= match.start() < end for start, end in occupied): | |
| candidates.append(match.group(0)) | |
| canonical_candidates = [ | |
| canonicalize_regulatory_reference(candidate) | |
| for candidate in candidates | |
| ] | |
| full_rule_suffixes = { | |
| item.split("-", 1)[1].casefold() | |
| for item in canonical_candidates | |
| if item and "-" in item | |
| } | |
| result: list[str] = [] | |
| seen: set[str] = set() | |
| for canonical in canonical_candidates: | |
| key = canonical.casefold() | |
| if not canonical: | |
| continue | |
| if "-" not in canonical and key in full_rule_suffixes: | |
| continue | |
| if key not in seen: | |
| seen.add(key) | |
| result.append(canonical) | |
| if len(result) >= limit: | |
| break | |
| return result | |
| def extract_regulatory_cross_references(chunks: list[dict]) -> list[str]: | |
| """Extract and canonicalize rule, section, table, and appendix leads.""" | |
| return normalize_regulatory_references( | |
| [str(chunk.get("text") or "") for chunk in chunks], | |
| limit=12, | |
| ) | |
| def normalize_string_list(value: Any) -> list[str]: | |
| """Normalize a model-produced string/list field to unique strings.""" | |
| if value is None: | |
| return [] | |
| if isinstance(value, str): | |
| raw_values = re.split(r"[\n,;]+", value) | |
| elif isinstance(value, (list, tuple, set)): | |
| raw_values = list(value) | |
| else: | |
| raw_values = [value] | |
| result: list[str] = [] | |
| seen: set[str] = set() | |
| for item in raw_values: | |
| text = re.sub(r"\s+", " ", str(item or "")).strip(" -\t") | |
| key = text.casefold() | |
| if text and key not in seen: | |
| seen.add(key) | |
| result.append(text) | |
| return result | |
| def looks_like_sql_query(query: str) -> bool: | |
| text = str(query or "") | |
| return bool(re.search(r"\b(?:select|from|where)\b|\w+\s*=", text, re.IGNORECASE)) | |
| def semantic_query_fallback( | |
| question: str, | |
| target_concept: str = "", | |
| cross_references: list[str] | None = None, | |
| next_search_focus: str = "", | |
| ) -> str: | |
| """Build a compact non-SQL query when model query generation fails.""" | |
| parts: list[str] = [] | |
| for value in [ | |
| *(normalize_regulatory_references(cross_references or [])[:2]), | |
| target_concept, | |
| next_search_focus, | |
| question, | |
| ]: | |
| text = re.sub(r"\s+", " ", str(value or "")).strip() | |
| if text and text.casefold() not in {part.casefold() for part in parts}: | |
| parts.append(text) | |
| return compact_semantic_query(" ".join(parts)) | |
| def build_exact_reference_query( | |
| reference: str, | |
| target_concept: str, | |
| question_type: str, | |
| ) -> str: | |
| """Build one compact citation-focused FAISS query.""" | |
| canonical = canonicalize_regulatory_reference(reference) | |
| evidence_hint = { | |
| "definition": "definition means defined as", | |
| "numeric_criterion": "value units criterion", | |
| "calculation": "formula calculation", | |
| "requirement": "requirement reduction allocation", | |
| "applicability": "applicability applies", | |
| "procedure": "procedure steps", | |
| "exception": "exception conditions", | |
| }.get(str(question_type or "").strip().lower(), "") | |
| return compact_semantic_query( | |
| " ".join(part for part in [canonical, target_concept, evidence_hint] if part) | |
| ) | |
| def has_explicit_definition_evidence( | |
| chunks: list[dict], | |
| target_concept: str, | |
| ) -> bool: | |
| """Check that a definition claim is backed by actual defining language.""" | |
| target = re.sub(r"\s+", " ", str(target_concept or "")).strip() | |
| if not target: | |
| return False | |
| variants = [target] | |
| shortened = re.sub( | |
| r"\s+(?:waters?|standards?|criteria|term|definition)$", | |
| "", | |
| target, | |
| flags=re.IGNORECASE, | |
| ).strip() | |
| if shortened and shortened.casefold() != target.casefold(): | |
| variants.append(shortened) | |
| patterns: list[str] = [] | |
| for variant in variants: | |
| escaped = re.escape(variant) | |
| patterns.extend([ | |
| rf'["β]?{escaped}["β]?\s+(?:shall\s+mean|means|is\s+defined\s+as|refers\s+to)\b', | |
| rf'(?:definition\s+of|define(?:s|d)?\s+)["β]?{escaped}["β]?\s*(?:is|as|:)\b', | |
| rf'["β]?{escaped}["β]?\s*[:β-]\s+\S+', | |
| ]) | |
| for chunk in chunks: | |
| text = re.sub(r"\s+", " ", str(chunk.get("text") or "")) | |
| for pattern in patterns: | |
| if re.search(pattern, text, flags=re.IGNORECASE): | |
| return True | |
| return False | |
| def format_uptime(seconds: float) -> str: | |
| seconds = max(0, int(seconds)) | |
| days, seconds = divmod(seconds, 86400) | |
| hours, seconds = divmod(seconds, 3600) | |
| minutes, seconds = divmod(seconds, 60) | |
| parts = [] | |
| if days: | |
| parts.append(f"{days}d") | |
| if hours or days: | |
| parts.append(f"{hours}h") | |
| if minutes or hours or days: | |
| parts.append(f"{minutes}m") | |
| parts.append(f"{seconds}s") | |
| return " ".join(parts) | |
| def gpu_status_lines() -> list[str]: | |
| if not torch.cuda.is_available(): | |
| return ["CUDA available: No"] | |
| device = torch.cuda.current_device() | |
| properties = torch.cuda.get_device_properties(device) | |
| gib = 1024**3 | |
| return [ | |
| "CUDA available: Yes", | |
| f"GPU: {properties.name}", | |
| f"GPU memory total: {properties.total_memory / gib:.2f} GB", | |
| f"GPU memory allocated: {torch.cuda.memory_allocated(device) / gib:.2f} GB", | |
| f"GPU memory reserved: {torch.cuda.memory_reserved(device) / gib:.2f} GB", | |
| ] | |
| def check_system_status() -> str: | |
| with _counter_lock: | |
| counters = ( | |
| _requests_started, | |
| _requests_completed, | |
| _requests_failed, | |
| ) | |
| loaded_codes = loaded_vector_db_codes() | |
| loaded_names = [jurisdiction_name(code) for code in loaded_codes] | |
| lines = [ | |
| f"Process ID: {os.getpid()}", | |
| f"Process uptime: {format_uptime(time.time() - _app_started_at)}", | |
| "Available jurisdictions: " | |
| + ", ".join( | |
| f"{details['name']} ({code.upper()})" | |
| for code, details in JURISDICTIONS.items() | |
| ), | |
| ] | |
| for code, details in JURISDICTIONS.items(): | |
| db_path = jurisdiction_db_path(code) | |
| lines.extend( | |
| [ | |
| f"{details['name']} database files: " | |
| + ("Ready" if database_files_ready(code) else "Missing index.faiss and/or index.pkl"), | |
| f"{details['name']} database path: {db_path}", | |
| f"{details['name']} vector database loaded in memory: " | |
| + ("Yes" if code in loaded_codes else "No"), | |
| ] | |
| ) | |
| lines.extend( | |
| [ | |
| "Loaded vector databases: " | |
| + (", ".join(loaded_names) if loaded_names else "None"), | |
| "LLM provider: Direct local Unsloth inference", | |
| f"LLM model: {LLM_MODEL_NAME}", | |
| f"Model loaded in memory: {'Yes' if is_model_loaded() else 'No'}", | |
| f"Model dtype: {str(MODEL_DTYPE).replace('torch.', '')}", | |
| f"4-bit loading: {'Yes' if LOAD_IN_4BIT else 'No'}", | |
| f"Embedding model: {EMBEDDING_MODEL_NAME}", | |
| f"Requests started: {counters[0]}", | |
| f"Requests completed: {counters[1]}", | |
| f"Requests failed/empty: {counters[2]}", | |
| ] | |
| ) | |
| return "\n".join(lines + gpu_status_lines()) | |