Michael commited on
Commit
4df3f85
Β·
1 Parent(s): 0d15c66
Files changed (3) hide show
  1. app.py +39 -120
  2. create_rag_retriever.py +205 -53
  3. dp_vocab.txt +1334 -46
app.py CHANGED
@@ -58,7 +58,7 @@ import datetime
58
  import gradio as gr
59
  from openai import OpenAI
60
  from langchain_community.embeddings import HuggingFaceEmbeddings
61
- from create_rag_retriever import load_retriever_components
62
  import numpy as np
63
  import hashlib
64
  from langchain_core.documents import Document
@@ -214,14 +214,14 @@ SCENARIO_FALLBACK_TWEET_PATHS = {
214
  # Default fallback tweet dataset (empty; populated per-scenario at runtime).
215
  FALLBACK_TWEET_DATA = []
216
 
217
- RAG_K = 60
218
  RAG_FETCH_K = 10000
219
  RAG_LINKAGE_STORED_EXCERPT_LENGTH = 500
220
  ATTR_INFERENCE_EVIDENCE_STORED_EXCERPT_LENGTH = 500
221
 
222
  # ── RAG Linkage Similarity Thresholds ────────────────────────
223
- ROUGE_L_THRESHOLD = 0.15 # Minimum ROUGE-L score (0.0-1.0)
224
- COSINE_SIM_THRESHOLD = 0.15 # Minimum cosine similarity (0.0-1.0)
225
  MIN_COMBINED_SCORE = 0.2 # Minimum combined similarity score
226
  ROUGE_WEIGHT = 0.3 # Weight for ROUGE-L in combined score
227
  COSINE_WEIGHT = 0.7 # Weight for cosine similarity in combined score
@@ -229,6 +229,9 @@ MIN_NGRAM_LENGTH = 4 # Minimum characters for n-gram matching
229
  MIN_NGRAM_WORDS = 4 # Minimum words in a phrase to highlight
230
  MAX_NGRAM_WORDS = 7 # Maximum words in a phrase to highlight
231
 
 
 
 
232
  # ── Privacy / Differential Privacy ───────────────────────────
233
  MAX_POSSIBLE_EPS = 100.0
234
  INFERENCE_LIFT_THRESHOLD = 0
@@ -1584,8 +1587,6 @@ def build_retriever_from_csv(csv_file_path, progress=None, user_id_col="user id"
1584
  HybridRetriever instance or None if failed
1585
  """
1586
  try:
1587
- from create_rag_retriever import HybridRetriever
1588
-
1589
  logger.info(f"Building retriever from CSV: {csv_file_path}")
1590
  if progress:
1591
  progress(0.25, desc="Loading CSV data...")
@@ -1868,108 +1869,22 @@ def strip_special_chars(text):
1868
  """Strip digits and special characters."""
1869
  return re.sub(r'[^a-zA-Z]', '', text.lower())
1870
 
1871
-
1872
- class HybridRetriever:
1873
- """Hybrid retriever (semantic + BM25 + entity)."""
1874
-
1875
- def __init__(self, vectorstore, bm25=None, entity_index=None, documents=None,
1876
- semantic_weight=0.4, bm25_weight=0.3, entity_weight=0.3):
1877
- self.vectorstore = vectorstore
1878
- self.bm25 = bm25
1879
- self.entity_index = entity_index or defaultdict(list)
1880
- self.documents = documents or []
1881
- self.semantic_weight = semantic_weight
1882
- self.bm25_weight = bm25_weight
1883
- self.entity_weight = entity_weight
1884
-
1885
- def retrieve(self, query, k=10, fetch_k=100):
1886
- """Hybrid retrieval."""
1887
- # Simplified: just use semantic search
1888
- # Full implementation would combine semantic + BM25 + entity
1889
- semantic_results = self.vectorstore.similarity_search(query, k=fetch_k)
1890
- return semantic_results[:k]
1891
-
1892
-
1893
- class DPRetriever:
1894
- """Differentially private retriever using exponential mechanism.
1895
-
1896
- Sensitivity is computed empirically from the actual utility range of the
1897
- candidate documents rather than a fixed constant. This data-adaptive
1898
- approach (Dwork & Roth 2014; Koga et al. 2024 "Privacy-preserving RAG
1899
- with DP") gives a tighter bound, improving the privacy-utility trade-off
1900
- without weakening the formal Ξ΅-DP guarantee.
1901
-
1902
- For the exponential mechanism the sensitivity Ξ”u of the utility function u
1903
- is defined as:
1904
- Ξ”u = max_{d, d'} |u(d, q) - u(d', q)|
1905
- When u(d, q) = max_dist - dist(d, q) (distance-to-similarity inversion),
1906
- Ξ”u equals the range of utilities across the candidate pool. We clamp it
1907
- to a configurable minimum (sensitivity_cap) to guard against degenerate
1908
- cases where all candidates are equidistant from the query.
1909
-
1910
- Parameters
1911
- ----------
1912
- base_retriever : HybridRetriever
1913
- The underlying retriever whose vectorstore provides FAISS scores.
1914
- epsilon : float
1915
- DP privacy budget. Smaller = stronger privacy.
1916
- sensitivity_cap : float
1917
- Floor value for the computed sensitivity. Set to a small positive
1918
- number (default 1e-3) so the mechanism stays well-defined even when
1919
- all utility values are identical. For most corpora the empirical
1920
- range will be far larger than this cap, so it has no practical effect.
1921
  """
 
1922
 
1923
- def __init__(self, base_retriever, epsilon=1.0, sensitivity_cap=1e-3):
1924
- self.base_retriever = base_retriever
1925
- self.epsilon = epsilon
1926
- self.sensitivity_cap = sensitivity_cap
1927
-
1928
- def retrieve(self, query, k=10, fetch_k=100, seed=None):
1929
- """Retrieve documents with differential privacy."""
1930
- if seed is not None:
1931
- np.random.seed(seed)
1932
-
1933
- # Get candidates
1934
- try:
1935
- candidates = self.base_retriever.vectorstore.similarity_search_with_score(
1936
- query, k=fetch_k
1937
- )
1938
- except:
1939
- # Fallback if vectorstore doesn't support scores
1940
- docs = self.base_retriever.vectorstore.similarity_search(query, k=fetch_k)
1941
- return docs[:k]
1942
-
1943
- if not candidates:
1944
- return []
1945
-
1946
- docs, base_scores = zip(*candidates)
1947
- base_scores = np.array(base_scores)
1948
 
1949
- # Convert L2 distances to similarities (higher is better)
1950
- if base_scores[0] >= base_scores[-1]:
1951
- utilities = base_scores.copy() # similarity scores – higher is better
1952
- else:
1953
- max_dist = base_scores.max() + 1e-10
1954
- utilities = max_dist - base_scores # distance scores – lower is better
1955
-
1956
- # ── Empirical sensitivity (Dwork & Roth 2014; Koga et al. 2024) ────
1957
- # Sensitivity = range of the utility function across the candidate pool.
1958
- # This is the tightest valid bound for the exponential mechanism when
1959
- # the utility function is score-based and bounded by the data at hand.
1960
- u_range = float(utilities.max() - utilities.min())
1961
- sensitivity = max(u_range, self.sensitivity_cap)
1962
-
1963
- # Exponential mechanism: P(d) ∝ exp(Ξ΅ Β· u(d) / 2Ξ”u)
1964
- probabilities = np.exp((self.epsilon * utilities) / (2.0 * sensitivity))
1965
- probabilities = probabilities / probabilities.sum()
1966
-
1967
- # Sample k documents without replacement
1968
- selected_indices = np.random.choice(
1969
- len(docs), size=min(k, len(docs)), replace=False, p=probabilities
1970
- )
1971
-
1972
- return [docs[i] for i in selected_indices]
1973
 
1974
 
1975
  # ============================================================
@@ -4229,21 +4144,25 @@ def process_message(user_input, use_rag, epsilon, model_str, show_tips, show_rag
4229
  logger.info(f"[LOCAL] RAG retrieval use_rag={use_rag}; retriever={retriever}")
4230
  if use_rag and retriever is not None:
4231
  try:
4232
- # if epsilon != float('inf'):
4233
- # logger.info(f" Using DP retrieval (Ξ΅={epsilon})")
4234
- # dp_retriever = DPRetriever(retriever, epsilon=epsilon)
4235
- # retrieved = dp_retriever.retrieve(user_input, k=RAG_K, fetch_k=RAG_FETCH_K)
4236
- # else:
4237
- # retrieved = retriever.retrieve(user_input, k=RAG_K)
4238
- retrieved = retriever.retrieve(llm_input, k=RAG_K)
4239
- logger.info(f" Using standard retrieval (Retrieval DP disabled)")
4240
- logger.info(f">>>>>>> RAG RETRIEVED: {retrieved}")
4241
- u_rag = [] # computed concurrently inside make_concurrent_llm_calls_optimized
4242
- retrieval_elapsed = time.time() - retrieval_start
4243
- # for r in retrieved:
4244
- # print(r)
4245
- # print("\n")
4246
- logger.info(f" βœ“ Retrieved {len(retrieved)} docs in {retrieval_elapsed:.2f}s (LOCAL)")
 
 
 
 
4247
  except Exception as e:
4248
  logger.info(f" βœ— RAG retrieval error: {e}")
4249
  retrieved = []
 
58
  import gradio as gr
59
  from openai import OpenAI
60
  from langchain_community.embeddings import HuggingFaceEmbeddings
61
+ from create_rag_retriever import load_retriever_components, DPRetriever, HybridRetriever
62
  import numpy as np
63
  import hashlib
64
  from langchain_core.documents import Document
 
214
  # Default fallback tweet dataset (empty; populated per-scenario at runtime).
215
  FALLBACK_TWEET_DATA = []
216
 
217
+ RAG_K = 50
218
  RAG_FETCH_K = 10000
219
  RAG_LINKAGE_STORED_EXCERPT_LENGTH = 500
220
  ATTR_INFERENCE_EVIDENCE_STORED_EXCERPT_LENGTH = 500
221
 
222
  # ── RAG Linkage Similarity Thresholds ────────────────────────
223
+ ROUGE_L_THRESHOLD = 0.16 # Minimum ROUGE-L score (0.0-1.0)
224
+ COSINE_SIM_THRESHOLD = 0.16 # Minimum cosine similarity (0.0-1.0)
225
  MIN_COMBINED_SCORE = 0.2 # Minimum combined similarity score
226
  ROUGE_WEIGHT = 0.3 # Weight for ROUGE-L in combined score
227
  COSINE_WEIGHT = 0.7 # Weight for cosine similarity in combined score
 
229
  MIN_NGRAM_WORDS = 4 # Minimum words in a phrase to highlight
230
  MAX_NGRAM_WORDS = 7 # Maximum words in a phrase to highlight
231
 
232
+ RAG_MIN_SIMILARITY_THRESHOLD = 0.25 # baseline threshold when DP is off
233
+ RAG_DP_THRESHOLD_SCALE = 1.5 # how fast the threshold rises as Ξ΅ falls
234
+
235
  # ── Privacy / Differential Privacy ───────────────────────────
236
  MAX_POSSIBLE_EPS = 100.0
237
  INFERENCE_LIFT_THRESHOLD = 0
 
1587
  HybridRetriever instance or None if failed
1588
  """
1589
  try:
 
 
1590
  logger.info(f"Building retriever from CSV: {csv_file_path}")
1591
  if progress:
1592
  progress(0.25, desc="Loading CSV data...")
 
1869
  """Strip digits and special characters."""
1870
  return re.sub(r'[^a-zA-Z]', '', text.lower())
1871
 
1872
+ def epsilon_adjusted_threshold(epsilon, base=RAG_MIN_SIMILARITY_THRESHOLD, scale=RAG_DP_THRESHOLD_SCALE):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1873
  """
1874
+ Compute a similarity threshold that tightens as epsilon falls.
1875
 
1876
+ At epsilon=inf (no DP) β†’ threshold = base (e.g. 0.30)
1877
+ At epsilon=1 β†’ threshold β‰ˆ base + 0.12 (e.g. 0.42)
1878
+ At epsilon=0.1 β†’ threshold β‰ˆ base + 0.29 (e.g. 0.59)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1879
 
1880
+ The log1p curve means the boost is largest at very small epsilon
1881
+ (strong privacy) and negligible at large epsilon (no privacy).
1882
+ The cap at 0.92 prevents the threshold from becoming unreachable.
1883
+ """
1884
+ if epsilon == float("inf"):
1885
+ return base
1886
+ boost = scale * math.log1p(1.0 / max(epsilon, 1e-6))
1887
+ return min(base + boost, 0.92)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1888
 
1889
 
1890
  # ============================================================
 
4144
  logger.info(f"[LOCAL] RAG retrieval use_rag={use_rag}; retriever={retriever}")
4145
  if use_rag and retriever is not None:
4146
  try:
4147
+ min_sim = epsilon_adjusted_threshold(epsilon)
4148
+ logger.info(" Using threshold-filtered retrieval (min_sim=%.3f, Ξ΅=%s)", min_sim, epsilon)
4149
+ if epsilon != float('inf'):
4150
+ # Layer 1: threshold filter
4151
+ # Layer 2: exponential-mechanism sampling (Retrieval DP)
4152
+ pre_filtered = retriever.retrieve(llm_input, k=RAG_FETCH_K, fetch_k=RAG_FETCH_K, min_similarity=min_sim)
4153
+ logger.info(f">>>>>>> RAG RETRIEVED pre_filtered: {retrieved}")
4154
+ if pre_filtered:
4155
+ dp_retriever = DPRetriever(retriever, epsilon=epsilon)
4156
+ # Pass pre-filtered docs only β€” DPRetriever re-samples from them
4157
+ retrieved = dp_retriever.retrieve(llm_input, k=RAG_K, fetch_k=len(pre_filtered))
4158
+ logger.info(f">>>>>>> RAG RETRIEVED post_filtered: {retrieved}")
4159
+ else:
4160
+ retrieved = []
4161
+ else:
4162
+ retrieved = retriever.retrieve(llm_input, k=RAG_K, fetch_k=RAG_FETCH_K, min_similarity=min_sim)
4163
+ logger.info(f">>>>>>> RAG RETRIEVED: {retrieved}")
4164
+ retrieval_elapsed = time.time() - retrieval_start
4165
+ logger.info(f" βœ“ Retrieved {len(retrieved)} docs in {retrieval_elapsed:.2f}s (LOCAL)")
4166
  except Exception as e:
4167
  logger.info(f" βœ— RAG retrieval error: {e}")
4168
  retrieved = []
create_rag_retriever.py CHANGED
@@ -1,4 +1,5 @@
1
  import logging
 
2
  import sys
3
  import os
4
  import re
@@ -216,8 +217,18 @@ def load_panorama_data():
216
 
217
  class HybridRetriever:
218
  """
219
- Hybrid retriever combining semantic, lexical, and entity-based search.
 
 
 
 
 
 
 
 
 
220
  """
 
221
  def __init__(
222
  self,
223
  documents,
@@ -270,6 +281,15 @@ class HybridRetriever:
270
  self.entity_index[clean_token].append(i)
271
  print(f" βœ“ Entity index built ({len(self.entity_index)} unique entities)")
272
 
 
 
 
 
 
 
 
 
 
273
  def _reciprocal_rank_fusion(self, rankings, k=60):
274
  """Combine multiple rankings using RRF."""
275
  scores = defaultdict(float)
@@ -286,41 +306,115 @@ class HybridRetriever:
286
  """Retrieve using only semantic search (for comparison)."""
287
  return self.vectorstore.similarity_search(query, k=k)
288
 
289
- def retrieve(self, query, k=10, fetch_k=100):
290
- """Hybrid retrieval combining semantic, BM25, and entity matching."""
291
- # 1. Semantic search
292
- semantic_results = self.vectorstore.similarity_search(query, k=fetch_k)
293
- semantic_ranking = list(range(len(semantic_results)))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
 
295
- # 2. BM25 search
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
296
  query_tokens = word_tokenize(query.lower())
297
  bm25_scores = self.bm25.get_scores(query_tokens)
298
  bm25_ranking = np.argsort(bm25_scores)[::-1][:fetch_k].tolist()
 
 
299
 
300
- # 3. Entity matching with stripped characters
301
  query_lower = query.lower()
302
  entity_matches = set()
303
-
304
- # Extract potential entities from query and strip special chars
305
- query_tokens_for_entity = re.split(r'[;,\s.!?]+', query_lower)
306
- for query_token in query_tokens_for_entity:
307
  clean_query_token = strip_special_chars(query_token)
308
  if len(clean_query_token) > 2:
309
- # Check if this cleaned token matches any entity
310
  for entity, doc_ids in self.entity_index.items():
311
  if clean_query_token in entity or entity in clean_query_token:
312
  entity_matches.update(doc_ids)
313
-
314
  entity_ranking = list(entity_matches)[:fetch_k]
 
 
315
 
316
- # Combine with RRF
317
- rankings = {
318
- "semantic": semantic_ranking,
319
- "bm25": bm25_ranking,
320
- "entity": entity_ranking,
321
- }
322
-
323
- # Weight rankings
324
  weighted_rankings = {}
325
  if self.semantic_weight > 0:
326
  weighted_rankings["semantic"] = semantic_ranking
@@ -330,11 +424,17 @@ class HybridRetriever:
330
  weighted_rankings["entity"] = entity_ranking
331
 
332
  scores, sources = self._reciprocal_rank_fusion(weighted_rankings)
333
-
334
- # Sort by score and return top-k documents
335
- sorted_doc_ids = sorted(scores.keys(), key=lambda x: scores[x], reverse=True)[:k]
336
-
337
- return [self.documents[i] for i in sorted_doc_ids]
 
 
 
 
 
 
338
 
339
 
340
  # ==============================================================================
@@ -342,54 +442,101 @@ class HybridRetriever:
342
  # ==============================================================================
343
 
344
  class DPRetriever:
345
- """Differentially private retriever using exponential mechanism."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
 
347
- def __init__(self, base_retriever, epsilon=1.0):
348
  self.base_retriever = base_retriever
349
  self.epsilon = epsilon
350
-
351
- def retrieve(self, query, k=10, fetch_k=100, method="exponential", seed=None,
352
- epsilon_total=None, track_budget=False, return_diagnostics=False):
353
- """
354
- Retrieve documents with differential privacy.
355
-
356
- Uses exponential mechanism to add noise to retrieval scores.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  """
358
- if epsilon_total is not None:
359
- epsilon = epsilon_total
360
- else:
361
- epsilon = self.epsilon
362
-
363
  if seed is not None:
364
  np.random.seed(seed)
365
 
366
- # Get candidate pool
367
- candidates = self.base_retriever.vectorstore.similarity_search_with_score(
368
- query, k=fetch_k
369
- )
 
 
 
 
 
370
 
371
  if not candidates:
372
  return []
373
 
374
- # Apply exponential mechanism
375
  docs, base_scores = zip(*candidates)
376
  base_scores = np.array(base_scores)
377
 
378
- # Convert distances to similarities (lower distance = higher similarity)
379
- max_dist = base_scores.max() + 1e-10
380
- utilities = max_dist - base_scores
 
 
 
 
 
381
 
382
- # Add noise using exponential mechanism
383
- sensitivity = 2.0 # Conservative estimate
 
384
 
385
- probabilities = np.exp((epsilon * utilities) / (2 * sensitivity))
 
386
  probabilities = probabilities / probabilities.sum()
387
 
388
  # Sample k documents without replacement
389
  selected_indices = np.random.choice(
390
  len(docs), size=min(k, len(docs)), replace=False, p=probabilities
391
  )
392
-
393
  return [docs[i] for i in selected_indices]
394
 
395
 
@@ -506,6 +653,11 @@ def build_documents(merged, users_df):
506
 
507
 
508
  if __name__ == "__main__":
 
 
 
 
 
509
  RETRIEVER_SAVE_PATH = r"C:\Users\user\Datasets\Panorama Synthetic Data RAG\faiss_panorama_retriever_components.pkl"
510
  if os.path.exists(RETRIEVER_SAVE_PATH):
511
  retriever = load_retriever_components(RETRIEVER_SAVE_PATH)
 
1
  import logging
2
+ import math
3
  import sys
4
  import os
5
  import re
 
217
 
218
  class HybridRetriever:
219
  """
220
+ Hybrid retriever combining semantic (FAISS), lexical (BM25), and
221
+ entity-based search with Reciprocal Rank Fusion (RRF).
222
+
223
+ The ``retrieve`` method accepts an optional ``min_similarity``
224
+ threshold. When set, only documents whose normalised semantic
225
+ similarity to the query meets or exceeds that value are eligible for
226
+ retrieval. This makes the system sensitive to Input-DP perturbation:
227
+ a heavily noised query will drift away from the persona corpus and
228
+ return fewer β€” or zero β€” documents, so the system's output correctly
229
+ reflects the privacy protection that is active.
230
  """
231
+
232
  def __init__(
233
  self,
234
  documents,
 
281
  self.entity_index[clean_token].append(i)
282
  print(f" βœ“ Entity index built ({len(self.entity_index)} unique entities)")
283
 
284
+ # ── Content-to-corpus-index lookup (used by threshold filtering) ──────
285
+ # Maps page_content β†’ list of corpus indices so that FAISS results
286
+ # (which are Document objects, not indices) can be mapped back to
287
+ # their position in self.documents. Duplicate page_content values
288
+ # are handled by storing all matching indices.
289
+ self._content_to_indices = defaultdict(list)
290
+ for i, doc in enumerate(self.documents):
291
+ self._content_to_indices[doc.page_content].append(i)
292
+
293
  def _reciprocal_rank_fusion(self, rankings, k=60):
294
  """Combine multiple rankings using RRF."""
295
  scores = defaultdict(float)
 
306
  """Retrieve using only semantic search (for comparison)."""
307
  return self.vectorstore.similarity_search(query, k=k)
308
 
309
+ def retrieve(self, query, k=10, fetch_k=100, min_similarity=None):
310
+ """Hybrid retrieval combining semantic, BM25, and entity matching.
311
+
312
+ Parameters
313
+ ----------
314
+ query : str
315
+ The search query (may be DP-perturbed).
316
+ k : int
317
+ Maximum number of documents to return.
318
+ fetch_k : int
319
+ Candidate pool size passed to FAISS.
320
+ min_similarity : float or None
321
+ When set, only documents whose normalised semantic similarity
322
+ to the query meets or exceeds this value are eligible.
323
+ Documents below the threshold are excluded from ALL three
324
+ ranking components (semantic, BM25, entity) before RRF.
325
+ Pass None (default) to disable filtering and preserve the
326
+ original behaviour.
327
+
328
+ Returns
329
+ -------
330
+ list[Document]
331
+ Up to k documents, potentially fewer (or empty) when
332
+ min_similarity is strict relative to the query.
333
+ """
334
+ # ── 1. Semantic search WITH scores ───────────────────────────────────
335
+ try:
336
+ candidates = self.vectorstore.similarity_search_with_score(
337
+ query, k=fetch_k
338
+ )
339
+ except Exception:
340
+ # Fallback: vectorstore does not expose scores β†’ no threshold
341
+ docs = self.vectorstore.similarity_search(query, k=fetch_k)
342
+ candidates = [(doc, 0.0) for doc in docs]
343
+
344
+ if not candidates:
345
+ return []
346
+
347
+ raw_docs, raw_scores = zip(*candidates)
348
+ raw_scores = list(raw_scores)
349
 
350
+ # ── Normalise scores to similarity ∈ [0, 1] ─────────────────────────
351
+ # FAISS/IndexFlatL2 returns L2 distances (ascending: closer = smaller).
352
+ # IndexFlatIP on normalised vectors returns cosine scores (descending).
353
+ if len(raw_scores) >= 2 and raw_scores[0] <= raw_scores[-1]:
354
+ # L2 distances: invert so that higher = more similar
355
+ max_dist = max(raw_scores) + 1e-10
356
+ similarities = [1.0 - s / max_dist for s in raw_scores]
357
+ else:
358
+ # Already similarity scores; clamp to [0, 1]
359
+ similarities = [max(0.0, min(1.0, s)) for s in raw_scores]
360
+
361
+ # ── Apply similarity threshold ────────────────────────────────────────
362
+ if min_similarity is not None:
363
+ passing_pairs = [
364
+ (doc, sim)
365
+ for doc, sim in zip(raw_docs, similarities)
366
+ if sim >= min_similarity
367
+ ]
368
+ if not passing_pairs:
369
+ logger.info(
370
+ " HybridRetriever: 0/%d candidates above threshold %.3f"
371
+ " β€” returning []",
372
+ len(raw_docs), min_similarity,
373
+ )
374
+ return []
375
+
376
+ # Build the set of *corpus* indices that passed the threshold.
377
+ # This is used to restrict BM25 and entity rankings to the
378
+ # same document subset, ensuring all three components only
379
+ # vote for threshold-passing documents.
380
+ valid_corpus_indices = set()
381
+ for doc, _ in passing_pairs:
382
+ for idx in self._content_to_indices.get(doc.page_content, []):
383
+ valid_corpus_indices.add(idx)
384
+
385
+ # Semantic ranking: use actual corpus indices for filtered docs
386
+ # so they are consistent with BM25/entity namespace.
387
+ semantic_ranking = []
388
+ for doc, _ in passing_pairs:
389
+ for idx in self._content_to_indices.get(doc.page_content, []):
390
+ semantic_ranking.append(idx)
391
+ break # one representative index per doc is enough for RRF
392
+ else:
393
+ # No threshold: preserve original behaviour (range-based indices).
394
+ valid_corpus_indices = None
395
+ semantic_ranking = list(range(len(raw_docs)))
396
+
397
+ # ── 2. BM25 search ───────────────────────────────────────────────────
398
  query_tokens = word_tokenize(query.lower())
399
  bm25_scores = self.bm25.get_scores(query_tokens)
400
  bm25_ranking = np.argsort(bm25_scores)[::-1][:fetch_k].tolist()
401
+ if valid_corpus_indices is not None:
402
+ bm25_ranking = [i for i in bm25_ranking if i in valid_corpus_indices]
403
 
404
+ # ── 3. Entity matching ───────────────────────────────────────────────
405
  query_lower = query.lower()
406
  entity_matches = set()
407
+ for query_token in re.split(r'[;,\s.!?]+', query_lower):
 
 
 
408
  clean_query_token = strip_special_chars(query_token)
409
  if len(clean_query_token) > 2:
 
410
  for entity, doc_ids in self.entity_index.items():
411
  if clean_query_token in entity or entity in clean_query_token:
412
  entity_matches.update(doc_ids)
 
413
  entity_ranking = list(entity_matches)[:fetch_k]
414
+ if valid_corpus_indices is not None:
415
+ entity_ranking = [i for i in entity_ranking if i in valid_corpus_indices]
416
 
417
+ # ── 4. Reciprocal Rank Fusion ─────────────────────────────────────────
 
 
 
 
 
 
 
418
  weighted_rankings = {}
419
  if self.semantic_weight > 0:
420
  weighted_rankings["semantic"] = semantic_ranking
 
424
  weighted_rankings["entity"] = entity_ranking
425
 
426
  scores, sources = self._reciprocal_rank_fusion(weighted_rankings)
427
+ sorted_doc_ids = sorted(
428
+ scores.keys(), key=lambda x: scores[x], reverse=True
429
+ )[:k]
430
+
431
+ result = [self.documents[i] for i in sorted_doc_ids]
432
+ logger.info(
433
+ " HybridRetriever: returning %d/%d docs (min_similarity=%s)",
434
+ len(result), len(candidates),
435
+ f"{min_similarity:.3f}" if min_similarity is not None else "None",
436
+ )
437
+ return result
438
 
439
 
440
  # ==============================================================================
 
442
  # ==============================================================================
443
 
444
  class DPRetriever:
445
+ """Differentially private retriever using the Exponential Mechanism.
446
+
447
+ Sensitivity is computed *empirically* from the actual utility range of
448
+ the candidate pool rather than a fixed constant. This data-adaptive
449
+ approach (Dwork & Roth 2014; Koga et al. 2024) gives a tighter bound,
450
+ improving the privacy-utility trade-off without weakening the formal
451
+ Ξ΅-DP guarantee.
452
+
453
+ For the exponential mechanism the sensitivity Ξ”u of utility function u is:
454
+ Ξ”u = max_{d, d'} |u(d, q) βˆ’ u(d', q)|
455
+ When u(d, q) = max_dist βˆ’ dist(d, q) (distance-to-similarity inversion),
456
+ Ξ”u equals the range of utilities across the candidate pool. We clamp it
457
+ to ``sensitivity_cap`` to guard against degenerate cases where all
458
+ candidates are equidistant from the query.
459
+
460
+ Parameters
461
+ ----------
462
+ base_retriever : HybridRetriever
463
+ The underlying retriever whose vectorstore provides FAISS scores.
464
+ epsilon : float
465
+ DP privacy budget. Smaller Ξ΅ β†’ stronger privacy.
466
+ sensitivity_cap : float
467
+ Floor value for the empirical sensitivity (default 1e-3). For
468
+ most corpora the empirical range will be far larger than this cap
469
+ so it has no practical effect.
470
+ """
471
 
472
+ def __init__(self, base_retriever, epsilon=1.0, sensitivity_cap=1e-3):
473
  self.base_retriever = base_retriever
474
  self.epsilon = epsilon
475
+ self.sensitivity_cap = sensitivity_cap
476
+
477
+ def retrieve(self, query, k=10, fetch_k=100, seed=None):
478
+ """Retrieve up to k documents with differential privacy.
479
+
480
+ Uses the Exponential Mechanism: each candidate document is sampled
481
+ with probability proportional to exp(Ξ΅ Β· u(d) / 2Ξ”u), where u is
482
+ the normalised similarity utility and Ξ”u is the empirical range.
483
+
484
+ Parameters
485
+ ----------
486
+ query : str
487
+ Search query (may be DP-perturbed).
488
+ k : int
489
+ Number of documents to return.
490
+ fetch_k : int
491
+ Candidate pool size fetched from FAISS before sampling.
492
+ seed : int or None
493
+ Optional random seed for reproducibility.
494
+
495
+ Returns
496
+ -------
497
+ list[Document]
498
+ k documents sampled with DP-weighted probabilities.
499
  """
 
 
 
 
 
500
  if seed is not None:
501
  np.random.seed(seed)
502
 
503
+ # Fetch candidate pool
504
+ try:
505
+ candidates = self.base_retriever.vectorstore.similarity_search_with_score(
506
+ query, k=fetch_k
507
+ )
508
+ except Exception:
509
+ # Fallback: vectorstore does not expose scores
510
+ docs = self.base_retriever.vectorstore.similarity_search(query, k=fetch_k)
511
+ return docs[:k]
512
 
513
  if not candidates:
514
  return []
515
 
 
516
  docs, base_scores = zip(*candidates)
517
  base_scores = np.array(base_scores)
518
 
519
+ # ── Convert raw scores to a utility where higher = better ────────────
520
+ # FAISS with L2: scores are distances (ascending) β†’ invert
521
+ # FAISS with IP: scores are similarities (descending) β†’ use as-is
522
+ if base_scores[0] >= base_scores[-1]:
523
+ utilities = base_scores.copy() # already similarity scores
524
+ else:
525
+ max_dist = base_scores.max() + 1e-10
526
+ utilities = max_dist - base_scores # invert L2 distances
527
 
528
+ # ── Empirical sensitivity (Dwork & Roth 2014; Koga et al. 2024) ─────
529
+ u_range = float(utilities.max() - utilities.min())
530
+ sensitivity = max(u_range, self.sensitivity_cap)
531
 
532
+ # ── Exponential mechanism: P(d) ∝ exp(Ξ΅ Β· u(d) / 2Ξ”u) ──────────────
533
+ probabilities = np.exp((self.epsilon * utilities) / (2.0 * sensitivity))
534
  probabilities = probabilities / probabilities.sum()
535
 
536
  # Sample k documents without replacement
537
  selected_indices = np.random.choice(
538
  len(docs), size=min(k, len(docs)), replace=False, p=probabilities
539
  )
 
540
  return [docs[i] for i in selected_indices]
541
 
542
 
 
653
 
654
 
655
  if __name__ == "__main__":
656
+ # retriever = load_retriever_components("./faiss_persona_sarah_chen_retriever_components.pkl")
657
+ retriever = load_retriever_components("./faiss_panorama_retriever_components.pkl")
658
+ # save_retriever_components(retriever, "./faiss_persona_sarah_chen_retriever_components.pkl")
659
+ save_retriever_components(retriever, "./faiss_panorama_retriever_components.pkl")
660
+
661
  RETRIEVER_SAVE_PATH = r"C:\Users\user\Datasets\Panorama Synthetic Data RAG\faiss_panorama_retriever_components.pkl"
662
  if os.path.exists(RETRIEVER_SAVE_PATH):
663
  retriever = load_retriever_components(RETRIEVER_SAVE_PATH)
dp_vocab.txt CHANGED
@@ -16,7 +16,6 @@ resident
16
  citizen
17
  participant
18
  contributor
19
- representative
20
  colleague
21
  client
22
  customer
@@ -35,7 +34,6 @@ associate
35
 
36
  # ── Age / life-stage ─────────────────────────────────────────────────────────
37
  young
38
- adult
39
  senior
40
  graduate
41
  student
@@ -43,8 +41,6 @@ retired
43
  veteran
44
  experienced
45
  junior
46
- entry-level
47
- mid-career
48
  established
49
  seasoned
50
  upcoming
@@ -54,12 +50,9 @@ elderly
54
  beginner
55
  intermediate
56
  advanced
57
- early-career
58
- late-career
59
  apprentice
60
  trainee
61
  postgraduate
62
- undergraduate
63
  freshman
64
  sophomore
65
  retiree
@@ -92,7 +85,6 @@ western
92
  central
93
  domestic
94
  overseas
95
- international
96
  remote
97
  nearby
98
  provincial
@@ -154,12 +146,9 @@ prosperous
154
  struggling
155
  secure
156
  insecure
157
- well-off
158
- underprivileged
159
  affluent
160
  cash
161
  fund
162
- capital
163
  asset
164
  liability
165
  revenue
@@ -172,7 +161,6 @@ benefit
172
  pension
173
  dividend
174
  interest
175
- tax
176
  insurance
177
 
178
  # ── Marital / relationship ────────────────────────────────────────────────────
@@ -186,9 +174,7 @@ companion
186
  household
187
  relationship
188
  personal
189
- close
190
  romantic
191
- domestic
192
  familial
193
  mutual
194
  shared
@@ -199,7 +185,6 @@ public
199
  exclusive
200
  casual
201
  serious
202
- stable
203
  supportive
204
  caring
205
  devoted
@@ -209,7 +194,6 @@ free
209
  # ── Work / profession ─────────────────────────────────────────────────────────
210
  working
211
  employed
212
- professional
213
  analyst
214
  researcher
215
  developer
@@ -229,7 +213,6 @@ technician
229
  advisor
230
  operator
231
  executive
232
- administrator
233
  instructor
234
  trainer
235
  officer
@@ -276,7 +259,6 @@ mental
276
  therapy
277
  medication
278
  recovery
279
- rehabilitation
280
  nutrition
281
  exercise
282
  diet
@@ -285,7 +267,6 @@ symptom
285
  diagnosis
286
  prescription
287
  procedure
288
- specialist
289
  consultation
290
  examination
291
  test
@@ -312,7 +293,6 @@ managed
312
  education
313
  learning
314
  training
315
- qualification
316
  certificate
317
  diploma
318
  degree
@@ -339,7 +319,6 @@ tuition
339
  enrollment
340
  graduation
341
  admission
342
- examination
343
  assignment
344
  project
345
  laboratory
@@ -353,7 +332,6 @@ problem
353
  solution
354
  issue
355
  topic
356
- subject
357
  matter
358
  experience
359
  perspective
@@ -371,7 +349,6 @@ change
371
  difference
372
  impact
373
  effect
374
- benefit
375
  risk
376
  option
377
  choice
@@ -380,22 +357,17 @@ step
380
  process
381
  method
382
  approach
383
- environment
384
  context
385
  background
386
  field
387
- sector
388
  industry
389
  role
390
  position
391
  task
392
- project
393
  goal
394
  target
395
  opportunity
396
  challenge
397
- lifestyle
398
- routine
399
  schedule
400
  activity
401
  factor
@@ -403,21 +375,18 @@ aspect
403
  element
404
  feature
405
  requirement
406
- condition
407
  circumstance
408
  resource
409
  support
410
  service
411
  system
412
  network
413
- community
414
  group
415
  organization
416
  institution
417
 
418
  # ── General adjectives ────────────────────────────────────────────────────────
419
  good
420
- bad
421
  great
422
  difficult
423
  easy
@@ -428,21 +397,15 @@ available
428
  common
429
  specific
430
  general
431
- personal
432
- public
433
- private
434
  current
435
  recent
436
  positive
437
  negative
438
  significant
439
- major
440
- minor
441
  various
442
  unique
443
  typical
444
  standard
445
- advanced
446
  basic
447
  complex
448
  simple
@@ -459,8 +422,6 @@ uncertain
459
  confident
460
  prepared
461
  qualified
462
- experienced
463
- knowledgeable
464
  skilled
465
  capable
466
  able
@@ -494,11 +455,9 @@ accessible
494
  # ── General verbs ─────────────────────────────────────────────────────────────
495
  work
496
  help
497
- support
498
  manage
499
  handle
500
  find
501
- use
502
  need
503
  want
504
  think
@@ -507,15 +466,12 @@ know
507
  understand
508
  consider
509
  believe
510
- try
511
  make
512
- get
513
  give
514
  take
515
  keep
516
  stay
517
  move
518
- change
519
  improve
520
  reduce
521
  increase
@@ -589,11 +545,9 @@ integrate
589
  connect
590
  link
591
  relate
592
- associate
593
  involve
594
  include
595
  exclude
596
- consider
597
  ignore
598
  focus
599
  prioritize
@@ -602,3 +556,1337 @@ adjust
602
  modify
603
  customize
604
  personalize
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  citizen
17
  participant
18
  contributor
 
19
  colleague
20
  client
21
  customer
 
34
 
35
  # ── Age / life-stage ─────────────────────────────────────────────────────────
36
  young
 
37
  senior
38
  graduate
39
  student
 
41
  veteran
42
  experienced
43
  junior
 
 
44
  established
45
  seasoned
46
  upcoming
 
50
  beginner
51
  intermediate
52
  advanced
 
 
53
  apprentice
54
  trainee
55
  postgraduate
 
56
  freshman
57
  sophomore
58
  retiree
 
85
  central
86
  domestic
87
  overseas
 
88
  remote
89
  nearby
90
  provincial
 
146
  struggling
147
  secure
148
  insecure
 
 
149
  affluent
150
  cash
151
  fund
 
152
  asset
153
  liability
154
  revenue
 
161
  pension
162
  dividend
163
  interest
 
164
  insurance
165
 
166
  # ── Marital / relationship ────────────────────────────────────────────────────
 
174
  household
175
  relationship
176
  personal
 
177
  romantic
 
178
  familial
179
  mutual
180
  shared
 
185
  exclusive
186
  casual
187
  serious
 
188
  supportive
189
  caring
190
  devoted
 
194
  # ── Work / profession ─────────────────────────────────────────────────────────
195
  working
196
  employed
 
197
  analyst
198
  researcher
199
  developer
 
213
  advisor
214
  operator
215
  executive
 
216
  instructor
217
  trainer
218
  officer
 
259
  therapy
260
  medication
261
  recovery
 
262
  nutrition
263
  exercise
264
  diet
 
267
  diagnosis
268
  prescription
269
  procedure
 
270
  consultation
271
  examination
272
  test
 
293
  education
294
  learning
295
  training
 
296
  certificate
297
  diploma
298
  degree
 
319
  enrollment
320
  graduation
321
  admission
 
322
  assignment
323
  project
324
  laboratory
 
332
  solution
333
  issue
334
  topic
 
335
  matter
336
  experience
337
  perspective
 
349
  difference
350
  impact
351
  effect
 
352
  risk
353
  option
354
  choice
 
357
  process
358
  method
359
  approach
 
360
  context
361
  background
362
  field
 
363
  industry
364
  role
365
  position
366
  task
 
367
  goal
368
  target
369
  opportunity
370
  challenge
 
 
371
  schedule
372
  activity
373
  factor
 
375
  element
376
  feature
377
  requirement
 
378
  circumstance
379
  resource
380
  support
381
  service
382
  system
383
  network
 
384
  group
385
  organization
386
  institution
387
 
388
  # ── General adjectives ────────────────────────────────────────────────────────
389
  good
 
390
  great
391
  difficult
392
  easy
 
397
  common
398
  specific
399
  general
 
 
 
400
  current
401
  recent
402
  positive
403
  negative
404
  significant
 
 
405
  various
406
  unique
407
  typical
408
  standard
 
409
  basic
410
  complex
411
  simple
 
422
  confident
423
  prepared
424
  qualified
 
 
425
  skilled
426
  capable
427
  able
 
455
  # ── General verbs ─────────────────────────────────────────────────────────────
456
  work
457
  help
 
458
  manage
459
  handle
460
  find
 
461
  need
462
  want
463
  think
 
466
  understand
467
  consider
468
  believe
 
469
  make
 
470
  give
471
  take
472
  keep
473
  stay
474
  move
 
475
  improve
476
  reduce
477
  increase
 
545
  connect
546
  link
547
  relate
 
548
  involve
549
  include
550
  exclude
 
551
  ignore
552
  focus
553
  prioritize
 
556
  modify
557
  customize
558
  personalize
559
+
560
+
561
+ # ===========================================================================
562
+ # AUGMENTED SECTION – stop-word-cleaned (1834 total)
563
+ # Generated : 2026-03-17 (stop words removed)
564
+ # Filter : 4-12 chars, alpha only, deduplicated
565
+ # ===========================================================================
566
+
567
+ # ── Extended medical / mental health ────────────────────────────────────
568
+ anxiety
569
+ depression
570
+ stress
571
+ disorder
572
+ psychiatric
573
+ psychiatrist
574
+ counseling
575
+ psychologist
576
+ dosage
577
+ refill
578
+ referral
579
+ prognosis
580
+ symptoms
581
+ procedures
582
+ cardiologist
583
+ neurologist
584
+ pediatrician
585
+ gynecologist
586
+ oncologist
587
+ radiologist
588
+ orthopedic
589
+ urologist
590
+ nephrologist
591
+ allergist
592
+ internist
593
+ pathologist
594
+ obstetrician
595
+ radiographer
596
+ occupational
597
+ speech
598
+ respiratory
599
+ cognitive
600
+ behavioral
601
+ telehealth
602
+ telemedicine
603
+ outpatient
604
+ inpatient
605
+ ambulatory
606
+ surgical
607
+ noninvasive
608
+ palliative
609
+ integrative
610
+ alternative
611
+ mindfulness
612
+ meditation
613
+ relaxation
614
+ breathing
615
+ insomnia
616
+ fatigue
617
+ migraine
618
+ headache
619
+ nausea
620
+ dizziness
621
+ vertigo
622
+ arthritis
623
+ diabetes
624
+ hypertension
625
+ asthma
626
+ obesity
627
+ anemia
628
+ thyroid
629
+ infection
630
+ inflammation
631
+ allergy
632
+ allergies
633
+ autoimmune
634
+ neurological
635
+ emotional
636
+ recurring
637
+ intermittent
638
+ progressive
639
+ degenerative
640
+ remission
641
+ relapse
642
+ healing
643
+ prevention
644
+ intervention
645
+ urine
646
+ stool
647
+ saliva
648
+ biopsy
649
+ imaging
650
+ ultrasound
651
+ mammogram
652
+ vaccine
653
+ vaccination
654
+ immunization
655
+ booster
656
+ antibody
657
+ antibiotics
658
+ antivirals
659
+ ward
660
+ emergency
661
+ intensive
662
+ obstetric
663
+ pediatric
664
+ geriatric
665
+ intake
666
+ discharge
667
+ aftercare
668
+ copay
669
+ deductible
670
+ premium
671
+ formulary
672
+ appeal
673
+ grievance
674
+ denial
675
+ approval
676
+ claim
677
+ stroke
678
+ tumor
679
+ cyst
680
+ polyp
681
+ ulcer
682
+ fracture
683
+ sprain
684
+ strain
685
+ concussion
686
+ laceration
687
+ bruising
688
+ swelling
689
+ redness
690
+ rash
691
+ burn
692
+ wound
693
+ scar
694
+ retention
695
+ edema
696
+ abscess
697
+ hernia
698
+ rupture
699
+ prolapse
700
+ dislocation
701
+ hemorrhage
702
+ bleeding
703
+ clotting
704
+ thrombosis
705
+ embolism
706
+ infarction
707
+ seizure
708
+ epilepsy
709
+ dementia
710
+ alzheimer
711
+ parkinson
712
+ sclerosis
713
+ fibromyalgia
714
+ lupus
715
+ psoriasis
716
+ eczema
717
+ rosacea
718
+ vitiligo
719
+ osteoporosis
720
+ rheumatoid
721
+ gout
722
+ tendinitis
723
+ bursitis
724
+ neuropathy
725
+ sciatica
726
+ scoliosis
727
+ kyphosis
728
+ herniated
729
+ tonsillitis
730
+ sinusitis
731
+ bronchitis
732
+ pneumonia
733
+ pleurisy
734
+ pericarditis
735
+ myocarditis
736
+ endocarditis
737
+ tachycardia
738
+ bradycardia
739
+ colonoscopy
740
+ endoscopy
741
+ gastroscopy
742
+ laparoscopy
743
+ arthroscopy
744
+ aspiration
745
+ drainage
746
+ irrigation
747
+ debridement
748
+ suturing
749
+ casting
750
+ splinting
751
+ traction
752
+ bracing
753
+ prosthetics
754
+ orthotics
755
+ chemotherapy
756
+ radiation
757
+ hormone
758
+ targeted
759
+ biological
760
+ robotic
761
+ intravenous
762
+ subcutaneous
763
+ topical
764
+ transdermal
765
+ inhaled
766
+ nebulized
767
+ sublingual
768
+
769
+ # ── Extended occupations and roles ──────────────────────────────────────
770
+ fisherman
771
+ fisher
772
+ farmer
773
+ rancher
774
+ shepherd
775
+ herder
776
+ forester
777
+ logger
778
+ miner
779
+ steelworker
780
+ welder
781
+ fabricator
782
+ machinist
783
+ millwright
784
+ carpenter
785
+ joiner
786
+ glazier
787
+ roofer
788
+ tiler
789
+ bricklayer
790
+ stonemason
791
+ plasterer
792
+ painter
793
+ decorator
794
+ upholsterer
795
+ floorer
796
+ landscaper
797
+ housekeeper
798
+ janitor
799
+ custodian
800
+ cleaner
801
+ launderer
802
+ tailor
803
+ seamstress
804
+ cobbler
805
+ jeweler
806
+ watchmaker
807
+ optician
808
+ audiologist
809
+ podiatrist
810
+ chiropractor
811
+ osteopath
812
+ naturopath
813
+ homeopath
814
+ midwife
815
+ paramedic
816
+ phlebotomist
817
+ firefighter
818
+ security
819
+ warden
820
+ ranger
821
+ inspector
822
+ customs
823
+ immigration
824
+ caseworker
825
+ probation
826
+ parole
827
+ advocate
828
+ mediator
829
+ interpreter
830
+ translator
831
+ editor
832
+ proofreader
833
+ publisher
834
+ illustrator
835
+ photographer
836
+ videographer
837
+ animator
838
+ filmmaker
839
+ producer
840
+ screenwriter
841
+ playwright
842
+ lyricist
843
+ composer
844
+ musician
845
+ performer
846
+ conductor
847
+ baker
848
+ confectioner
849
+ pastry
850
+ butcher
851
+ fishmonger
852
+ greengrocer
853
+ grocer
854
+ barista
855
+ bartender
856
+ waiter
857
+ waitress
858
+ host
859
+ hostess
860
+ concierge
861
+ actuary
862
+ broker
863
+ dealer
864
+ investor
865
+ recruiter
866
+ headhunter
867
+ marketer
868
+ advertiser
869
+ publicist
870
+ influencer
871
+ strategist
872
+ fundraiser
873
+ politician
874
+ legislator
875
+ diplomat
876
+ ambassador
877
+ consul
878
+ professor
879
+ lecturer
880
+ tutor
881
+ mentor
882
+ facilitator
883
+ principal
884
+ provost
885
+ chancellor
886
+
887
+ # ── Family and relationships ────────────────────────────────────────────
888
+ spouse
889
+ husband
890
+ wife
891
+ girlfriend
892
+ boyfriend
893
+ fiancee
894
+ parent
895
+ mother
896
+ father
897
+ daughter
898
+ sibling
899
+ brother
900
+ sister
901
+ child
902
+ grandparent
903
+ grandmother
904
+ grandfather
905
+ grandchild
906
+ grandson
907
+ uncle
908
+ aunt
909
+ nephew
910
+ niece
911
+ cousin
912
+ relative
913
+ caregiver
914
+ guardian
915
+ stepparent
916
+ stepmother
917
+ stepfather
918
+ stepchild
919
+ stepsibling
920
+ foster
921
+ adoptive
922
+ extended
923
+ nuclear
924
+ blended
925
+ dependent
926
+ beneficiary
927
+ divorced
928
+ widowed
929
+ separated
930
+ remarried
931
+ cohabiting
932
+ engaged
933
+ friendship
934
+ mentorship
935
+ roommate
936
+ housemate
937
+ flatmate
938
+
939
+ # ── Common adverbs and qualifiers ───────────────────────────────────────
940
+ currently
941
+ previously
942
+ formerly
943
+ typically
944
+ regularly
945
+ consistently
946
+ occasionally
947
+ partly
948
+ gradually
949
+ carefully
950
+ thoroughly
951
+ properly
952
+ directly
953
+ indirectly
954
+ actively
955
+ passively
956
+ openly
957
+ privately
958
+ publicly
959
+ formally
960
+ informally
961
+ personally
962
+ academically
963
+ financially
964
+ medically
965
+ legally
966
+ locally
967
+ nationally
968
+ regionally
969
+ globally
970
+ remotely
971
+ immediately
972
+ urgently
973
+ eventually
974
+ ultimately
975
+ initially
976
+ obviously
977
+ seemingly
978
+ reportedly
979
+ roughly
980
+ precisely
981
+ adequately
982
+ sufficiently
983
+ strongly
984
+ weakly
985
+ moderately
986
+ increasingly
987
+ effectively
988
+ efficiently
989
+ successfully
990
+ voluntarily
991
+ separately
992
+ individually
993
+ collectively
994
+
995
+ # ── Extended location and geography ─────────────────────────────────────
996
+ street
997
+ avenue
998
+ boulevard
999
+ highway
1000
+ trail
1001
+ apartment
1002
+ suite
1003
+ building
1004
+ campus
1005
+ compound
1006
+ workplace
1007
+ factory
1008
+ warehouse
1009
+ depot
1010
+ terminal
1011
+ station
1012
+ airport
1013
+ seaport
1014
+ harbor
1015
+ suburban
1016
+ exurban
1017
+ parish
1018
+ province
1019
+ canton
1020
+ department
1021
+ continent
1022
+ hemisphere
1023
+ equatorial
1024
+ tropical
1025
+ subtropical
1026
+ temperate
1027
+ arctic
1028
+ alpine
1029
+ inland
1030
+ riverside
1031
+ lakeside
1032
+ hillside
1033
+ uptown
1034
+ midtown
1035
+ periphery
1036
+ fringe
1037
+ northeast
1038
+ northwest
1039
+ southeast
1040
+ southwest
1041
+ midwestern
1042
+ pacific
1043
+ atlantic
1044
+ caribbean
1045
+ scandinavian
1046
+
1047
+ # ── Technology and digital ──────────────────────────────────────────���───
1048
+ computer
1049
+ laptop
1050
+ tablet
1051
+ smartphone
1052
+ device
1053
+ keyboard
1054
+ internet
1055
+ wireless
1056
+ broadband
1057
+ fiber
1058
+ cable
1059
+ satellite
1060
+ software
1061
+ hardware
1062
+ platform
1063
+ application
1064
+ database
1065
+ server
1066
+ cloud
1067
+ storage
1068
+ backup
1069
+ encryption
1070
+ privacy
1071
+ firewall
1072
+ website
1073
+ browser
1074
+ search
1075
+ email
1076
+ messaging
1077
+ online
1078
+ virtual
1079
+ hybrid
1080
+ distributed
1081
+ asynchronous
1082
+ productivity
1083
+ coordination
1084
+ workflow
1085
+ account
1086
+ profile
1087
+ login
1088
+ password
1089
+ username
1090
+ credential
1091
+ notification
1092
+ alert
1093
+ reminder
1094
+ calendar
1095
+ spreadsheet
1096
+ presentation
1097
+ archive
1098
+ video
1099
+ audio
1100
+ podcast
1101
+ streaming
1102
+ broadcast
1103
+ recording
1104
+ playback
1105
+ algorithm
1106
+ automation
1107
+ analytics
1108
+ dashboard
1109
+ reporting
1110
+ insight
1111
+ upgrade
1112
+ update
1113
+ patch
1114
+ version
1115
+ release
1116
+ deployment
1117
+ maintenance
1118
+ subscription
1119
+ license
1120
+ membership
1121
+
1122
+ # ── Insurance legal and finance extension ───────────────────────────────
1123
+ coverage
1124
+ coinsurance
1125
+ qualifying
1126
+ provider
1127
+ generic
1128
+ gatekeeper
1129
+ medicaid
1130
+ medicare
1131
+ marketplace
1132
+ exchange
1133
+ annuity
1134
+ portfolio
1135
+ equity
1136
+ bond
1137
+ yield
1138
+ allocation
1139
+ rebalancing
1140
+ withdrawal
1141
+ deposit
1142
+ contribution
1143
+ retirement
1144
+ checking
1145
+ overdraft
1146
+ statement
1147
+ transaction
1148
+ merchant
1149
+ vendor
1150
+ payee
1151
+ credit
1152
+ debit
1153
+ outstanding
1154
+ amortization
1155
+ refinance
1156
+ consolidate
1157
+ bankruptcy
1158
+ foreclosure
1159
+ garnishment
1160
+ lien
1161
+ collateral
1162
+ compliance
1163
+ regulation
1164
+ statute
1165
+ ordinance
1166
+ jurisdiction
1167
+ negligence
1168
+ indemnity
1169
+ warranty
1170
+ guarantee
1171
+ remedy
1172
+ arbitration
1173
+ mediation
1174
+ litigation
1175
+ judgment
1176
+ contract
1177
+ clause
1178
+ amendment
1179
+ addendum
1180
+ disclosure
1181
+ consent
1182
+ waiver
1183
+ notarize
1184
+ certify
1185
+ authenticate
1186
+ witness
1187
+
1188
+ # ── Social and community ────────────────────────────────────────────────
1189
+ nonprofit
1190
+ charity
1191
+ foundation
1192
+ committee
1193
+ council
1194
+ coalition
1195
+ alliance
1196
+ partnership
1197
+ outreach
1198
+ engagement
1199
+ advocacy
1200
+ awareness
1201
+ campaign
1202
+ initiative
1203
+ hotline
1204
+ helpline
1205
+ diversity
1206
+ inclusion
1207
+ belonging
1208
+ cultural
1209
+ linguistic
1210
+ religious
1211
+ ethnic
1212
+ marginalized
1213
+ underserved
1214
+ vulnerable
1215
+ empowerment
1216
+ resilience
1217
+ capacity
1218
+ civic
1219
+ democracy
1220
+ policy
1221
+ reform
1222
+ legislation
1223
+ grassroots
1224
+ stakeholder
1225
+
1226
+ # ── Work environment and employment ─────────────────────────────────────
1227
+ bonus
1228
+ incentive
1229
+ commission
1230
+ overtime
1231
+ fulltime
1232
+ permanent
1233
+ seasonal
1234
+ freelance
1235
+ onsite
1236
+ promotion
1237
+ demotion
1238
+ transfer
1239
+ reassignment
1240
+ rotation
1241
+ performance
1242
+ evaluation
1243
+ appraisal
1244
+ feedback
1245
+ milestone
1246
+ objective
1247
+ metric
1248
+ competency
1249
+ assessment
1250
+ onboarding
1251
+ orientation
1252
+ shadowing
1253
+ offboarding
1254
+ resignation
1255
+ termination
1256
+ redundancy
1257
+ layoff
1258
+ severance
1259
+ union
1260
+ bargaining
1261
+ dispute
1262
+ harassment
1263
+ retaliation
1264
+ ethics
1265
+ conduct
1266
+ integrity
1267
+ transparency
1268
+ governance
1269
+ culture
1270
+ leadership
1271
+ hierarchy
1272
+ division
1273
+ squad
1274
+ forecast
1275
+ headcount
1276
+ procurement
1277
+ supplier
1278
+ outsourcing
1279
+ audit
1280
+ quality
1281
+ intellectual
1282
+ patent
1283
+ trademark
1284
+ copyright
1285
+ licensing
1286
+ royalty
1287
+
1288
+ # ── Education extended ──────────────────────────────────────────────────
1289
+ literacy
1290
+ numeracy
1291
+ creativity
1292
+ teamwork
1293
+ media
1294
+ kindergarten
1295
+ elementary
1296
+ vocational
1297
+ polytechnic
1298
+ flipped
1299
+ mastery
1300
+ syllabus
1301
+ rubric
1302
+ formative
1303
+ summative
1304
+ diagnostic
1305
+ authentic
1306
+ tutorial
1307
+ discussion
1308
+ textbook
1309
+ workbook
1310
+ journal
1311
+ article
1312
+ fellowship
1313
+ recognition
1314
+ articulation
1315
+ registration
1316
+ deferral
1317
+ suspension
1318
+ expulsion
1319
+ commencement
1320
+ alumni
1321
+ career
1322
+ placement
1323
+ internship
1324
+ cooperative
1325
+ volunteering
1326
+
1327
+ # ── Common general nouns ────────────────────────────────────────────────
1328
+ ability
1329
+ absence
1330
+ accident
1331
+ achievement
1332
+ action
1333
+ addition
1334
+ advantage
1335
+ affair
1336
+ agreement
1337
+ argument
1338
+ assistance
1339
+ attention
1340
+ attitude
1341
+ authority
1342
+ barrier
1343
+ behavior
1344
+ board
1345
+ body
1346
+ branch
1347
+ category
1348
+ cause
1349
+ ceiling
1350
+ chapter
1351
+ character
1352
+ class
1353
+ climate
1354
+ comment
1355
+ commitment
1356
+ component
1357
+ conference
1358
+ conflict
1359
+ conversation
1360
+ corporation
1361
+ deadline
1362
+ debate
1363
+ demand
1364
+ description
1365
+ destination
1366
+ detail
1367
+ direction
1368
+ display
1369
+ distance
1370
+ distribution
1371
+ domain
1372
+ draft
1373
+ duration
1374
+ duty
1375
+ emphasis
1376
+ employment
1377
+ energy
1378
+ entrance
1379
+ entry
1380
+ exception
1381
+ existence
1382
+ expansion
1383
+ explanation
1384
+ extension
1385
+ failure
1386
+ figure
1387
+ format
1388
+ framework
1389
+ function
1390
+ funding
1391
+ generation
1392
+ guidance
1393
+ habit
1394
+ history
1395
+ identity
1396
+ importance
1397
+ impression
1398
+ indicator
1399
+ information
1400
+ inspection
1401
+ integration
1402
+ intention
1403
+ interview
1404
+ involvement
1405
+ language
1406
+ layer
1407
+ lesson
1408
+ limitation
1409
+ management
1410
+ manner
1411
+ margin
1412
+ meaning
1413
+ mechanism
1414
+ meeting
1415
+ mention
1416
+ mission
1417
+ mixture
1418
+ modification
1419
+ moment
1420
+ movement
1421
+ nature
1422
+ obligation
1423
+ observation
1424
+ occasion
1425
+ overview
1426
+ ownership
1427
+ pattern
1428
+ period
1429
+ phase
1430
+ practice
1431
+ presence
1432
+ priority
1433
+ production
1434
+ progress
1435
+ provision
1436
+ quantity
1437
+ range
1438
+ rate
1439
+ reaction
1440
+ reason
1441
+ reference
1442
+ relevance
1443
+ response
1444
+ revision
1445
+ selection
1446
+ shortage
1447
+ space
1448
+ status
1449
+ strategy
1450
+ strength
1451
+ structure
1452
+ substance
1453
+ summary
1454
+ timeline
1455
+ transition
1456
+ trend
1457
+ uncertainty
1458
+ validation
1459
+ value
1460
+ variety
1461
+ vision
1462
+ volume
1463
+
1464
+ # ── Common general adjectives ───────────────���───────────────────────────
1465
+ absolute
1466
+ acceptable
1467
+ accurate
1468
+ actual
1469
+ additional
1470
+ adverse
1471
+ annual
1472
+ applicable
1473
+ approximate
1474
+ aware
1475
+ balanced
1476
+ brief
1477
+ broad
1478
+ careful
1479
+ clear
1480
+ consistent
1481
+ continuous
1482
+ correct
1483
+ critical
1484
+ decisive
1485
+ detailed
1486
+ distinct
1487
+ diverse
1488
+ dominant
1489
+ dynamic
1490
+ essential
1491
+ exact
1492
+ existing
1493
+ expected
1494
+ extensive
1495
+ external
1496
+ extreme
1497
+ fair
1498
+ familiar
1499
+ frequent
1500
+ fundamental
1501
+ genuine
1502
+ global
1503
+ gradual
1504
+ growing
1505
+ helpful
1506
+ historical
1507
+ immediate
1508
+ inclusive
1509
+ initial
1510
+ integrated
1511
+ internal
1512
+ logical
1513
+ meaningful
1514
+ minimal
1515
+ national
1516
+ natural
1517
+ notable
1518
+ original
1519
+ partial
1520
+ potential
1521
+ primary
1522
+ proper
1523
+ reasonable
1524
+ remaining
1525
+ responsive
1526
+ similar
1527
+ structured
1528
+ successful
1529
+ sustainable
1530
+ systemic
1531
+ thorough
1532
+ timely
1533
+ transparent
1534
+ valid
1535
+ vital
1536
+ voluntary
1537
+ widespread
1538
+ neutral
1539
+ open
1540
+ profound
1541
+ rapid
1542
+ realistic
1543
+ regular
1544
+ related
1545
+ robust
1546
+ sensitive
1547
+ sharp
1548
+ solid
1549
+ strict
1550
+ superior
1551
+ systematic
1552
+ tender
1553
+ total
1554
+ universal
1555
+ updated
1556
+ useful
1557
+ verbal
1558
+ vertical
1559
+ visible
1560
+ visual
1561
+ vocal
1562
+ written
1563
+ functional
1564
+ interactive
1565
+ legitimate
1566
+ measurable
1567
+ operational
1568
+ parallel
1569
+
1570
+ # ── Common general verbs ────────────────────────────────────────────────
1571
+ accept
1572
+ acknowledge
1573
+ acquire
1574
+ activate
1575
+ affect
1576
+ affirm
1577
+ align
1578
+ allocate
1579
+ allow
1580
+ announce
1581
+ approve
1582
+ assign
1583
+ assist
1584
+ attain
1585
+ authorize
1586
+ avoid
1587
+ begin
1588
+ calculate
1589
+ check
1590
+ clarify
1591
+ classify
1592
+ collect
1593
+ confirm
1594
+ control
1595
+ convert
1596
+ convey
1597
+ cooperate
1598
+ define
1599
+ depend
1600
+ designate
1601
+ direct
1602
+ enable
1603
+ establish
1604
+ expand
1605
+ extend
1606
+ follow
1607
+ formulate
1608
+ fulfill
1609
+ generate
1610
+ guide
1611
+ highlight
1612
+ incorporate
1613
+ indicate
1614
+ inform
1615
+ introduce
1616
+ launch
1617
+ leverage
1618
+ listen
1619
+ locate
1620
+ meet
1621
+ minimize
1622
+ negotiate
1623
+ notify
1624
+ operate
1625
+ outline
1626
+ prepare
1627
+ proceed
1628
+ promote
1629
+ protect
1630
+ publish
1631
+ pursue
1632
+ raise
1633
+ recognize
1634
+ recruit
1635
+ refer
1636
+ reflect
1637
+ retain
1638
+ select
1639
+ send
1640
+ serve
1641
+ solve
1642
+ specify
1643
+ standardize
1644
+ strengthen
1645
+ streamline
1646
+ validate
1647
+ verify
1648
+ welcome
1649
+ capture
1650
+ commit
1651
+ continue
1652
+ discover
1653
+ educate
1654
+ empower
1655
+ enhance
1656
+ examine
1657
+ express
1658
+ gather
1659
+ invest
1660
+ justify
1661
+ motivate
1662
+ observe
1663
+ overcome
1664
+ prevent
1665
+ produce
1666
+ reach
1667
+ realize
1668
+ regulate
1669
+ reinforce
1670
+ represent
1671
+ restore
1672
+ seek
1673
+ simplify
1674
+ stimulate
1675
+ sustain
1676
+ tackle
1677
+ utilize
1678
+
1679
+ # ── Broad common English words ──────────────────────────────────────────
1680
+ abroad
1681
+ admit
1682
+ adopt
1683
+ advance
1684
+ advice
1685
+ afraid
1686
+ agree
1687
+ alarm
1688
+ almost
1689
+ amount
1690
+ anger
1691
+ animal
1692
+ appear
1693
+ arise
1694
+ arrive
1695
+ assume
1696
+ attach
1697
+ attack
1698
+ attend
1699
+ attract
1700
+ basis
1701
+ birth
1702
+ block
1703
+ break
1704
+ bring
1705
+ burst
1706
+ calm
1707
+ carry
1708
+ cease
1709
+ certain
1710
+ chain
1711
+ chair
1712
+ charge
1713
+ chart
1714
+ cheap
1715
+ chief
1716
+ clean
1717
+ cloth
1718
+ coast
1719
+ color
1720
+ compete
1721
+ content
1722
+ copy
1723
+ core
1724
+ count
1725
+ cover
1726
+ crime
1727
+ cross
1728
+ crowd
1729
+ daily
1730
+ damage
1731
+ dead
1732
+ deal
1733
+ dear
1734
+ deep
1735
+ delay
1736
+ differ
1737
+ divide
1738
+ doubt
1739
+ draw
1740
+ drive
1741
+ early
1742
+ earth
1743
+ effort
1744
+ enter
1745
+ error
1746
+ event
1747
+ example
1748
+ exist
1749
+ face
1750
+ fall
1751
+ false
1752
+ favor
1753
+ fight
1754
+ file
1755
+ fire
1756
+ fixed
1757
+ force
1758
+ form
1759
+ front
1760
+ given
1761
+ glass
1762
+ growth
1763
+ happy
1764
+ heard
1765
+ heavy
1766
+ hold
1767
+ house
1768
+ ideal
1769
+ image
1770
+ large
1771
+ legal
1772
+ light
1773
+ limit
1774
+ little
1775
+ lower
1776
+ model
1777
+ night
1778
+ north
1779
+ noted
1780
+ phone
1781
+ press
1782
+ prove
1783
+ pull
1784
+ push
1785
+ recall
1786
+ remain
1787
+ remove
1788
+ return
1789
+ right
1790
+ river
1791
+ road
1792
+ room
1793
+ round
1794
+ route
1795
+ save
1796
+ seem
1797
+ sense
1798
+ short
1799
+ sleep
1800
+ small
1801
+ south
1802
+ speak
1803
+ spend
1804
+ staff
1805
+ stand
1806
+ store
1807
+ style
1808
+ term
1809
+ thick
1810
+ train
1811
+ trial
1812
+ true
1813
+ trust
1814
+ usual
1815
+ visit
1816
+ voice
1817
+ watch
1818
+ water
1819
+ whole
1820
+ word
1821
+ write
1822
+ zero
1823
+ alone
1824
+ deeply
1825
+ hard
1826
+ likely
1827
+ sometimes
1828
+ back
1829
+ base
1830
+ best
1831
+ care
1832
+ case
1833
+ date
1834
+ done
1835
+ fact
1836
+ fail
1837
+ fast
1838
+ fill
1839
+ firm
1840
+ fish
1841
+ flow
1842
+ food
1843
+ full
1844
+ gain
1845
+ head
1846
+ high
1847
+ home
1848
+ hope
1849
+ hour
1850
+ kind
1851
+ land
1852
+ late
1853
+ lead
1854
+ life
1855
+ like
1856
+ line
1857
+ live
1858
+ look
1859
+ mark
1860
+ mean
1861
+ mind
1862
+ miss
1863
+ name
1864
+ news
1865
+ note
1866
+ page
1867
+ pain
1868
+ part
1869
+ past
1870
+ play
1871
+ poor
1872
+ read
1873
+ real
1874
+ rule
1875
+ safe
1876
+ self
1877
+ show
1878
+ sign
1879
+ slow
1880
+ sort
1881
+ talk
1882
+ team
1883
+ tell
1884
+ turn
1885
+ type
1886
+ wait
1887
+ walk
1888
+ warm
1889
+ weak
1890
+ week
1891
+ wish
1892
+ year