Commit ·
bf57d15
1
Parent(s): 29b3425
feat(autocomplete): threshold=0.05 + max 3 suggestions
Browse files- Added self.threshold=0.05 — suggestions with score < 0.05 are filtered
- Changed default n from 5 to 3 everywhere (service, API, frontend)
- Threshold applied in _bigram_predict, _hybrid_predict, and GPT-2 fallback
- src/app.py +1 -1
- src/js/autocomplete.js +1 -1
- src/nlp/autocomplete/autocomplete_service.py +10 -3
src/app.py
CHANGED
|
@@ -438,7 +438,7 @@ def autocomplete():
|
|
| 438 |
|
| 439 |
data = request.get_json()
|
| 440 |
context = data.get('context', '').strip()
|
| 441 |
-
n = int(data.get('n',
|
| 442 |
|
| 443 |
if not context or len(context) < 3:
|
| 444 |
return jsonify({'suggestions': [], 'status': 'success'})
|
|
|
|
| 438 |
|
| 439 |
data = request.get_json()
|
| 440 |
context = data.get('context', '').strip()
|
| 441 |
+
n = int(data.get('n', 3))
|
| 442 |
|
| 443 |
if not context or len(context) < 3:
|
| 444 |
return jsonify({'suggestions': [], 'status': 'success'})
|
src/js/autocomplete.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
| 11 |
// ─── Configuration ───────────────────────────────────────────────
|
| 12 |
const DEBOUNCE_MS = 400;
|
| 13 |
const MIN_CONTEXT_LEN = 3;
|
| 14 |
-
const MAX_SUGGESTIONS =
|
| 15 |
const CONTEXT_CHARS = 200;
|
| 16 |
|
| 17 |
// ─── State ───────────────────────────────────────────────────────
|
|
|
|
| 11 |
// ─── Configuration ───────────────────────────────────────────────
|
| 12 |
const DEBOUNCE_MS = 400;
|
| 13 |
const MIN_CONTEXT_LEN = 3;
|
| 14 |
+
const MAX_SUGGESTIONS = 3;
|
| 15 |
const CONTEXT_CHARS = 200;
|
| 16 |
|
| 17 |
// ─── State ───────────────────────────────────────────────────────
|
src/nlp/autocomplete/autocomplete_service.py
CHANGED
|
@@ -75,6 +75,7 @@ class HybridAutoComplete:
|
|
| 75 |
self.gpt2_model = None
|
| 76 |
self.device = "cpu"
|
| 77 |
self.alpha = 0.4 # Weight: 40% bigram, 60% GPT-2 (GPT-2 has context!)
|
|
|
|
| 78 |
self._cache = {}
|
| 79 |
self._cache_max = 256
|
| 80 |
|
|
@@ -135,7 +136,7 @@ class HybridAutoComplete:
|
|
| 135 |
|
| 136 |
# ─── Prediction ───────────────────────────────────────────────────────
|
| 137 |
|
| 138 |
-
def predict(self, context: str, n: int =
|
| 139 |
"""
|
| 140 |
Get top-N autocomplete suggestions for the given context.
|
| 141 |
|
|
@@ -176,7 +177,7 @@ class HybridAutoComplete:
|
|
| 176 |
logger.error(f"AutoComplete prediction error: {e}")
|
| 177 |
return []
|
| 178 |
|
| 179 |
-
def _bigram_predict(self, context: str, n: int =
|
| 180 |
"""Statistical-only prediction using bigram model."""
|
| 181 |
from .autocomplete_rules import merge_similar_predictions, filter_suggestions
|
| 182 |
|
|
@@ -212,10 +213,12 @@ class HybridAutoComplete:
|
|
| 212 |
preds.sort(key=lambda x: x[1], reverse=True)
|
| 213 |
preds = merge_similar_predictions(preds, top_k=n * 3)
|
| 214 |
preds = filter_suggestions(preds)
|
|
|
|
|
|
|
| 215 |
|
| 216 |
return [w for w, _ in preds[:n]]
|
| 217 |
|
| 218 |
-
def _hybrid_predict(self, context: str, n: int =
|
| 219 |
"""Hybrid prediction: bigram + GPT-2 scoring.
|
| 220 |
|
| 221 |
GPT-2 receives the FULL sentence as context for true context awareness.
|
|
@@ -248,6 +251,7 @@ class HybridAutoComplete:
|
|
| 248 |
if gpt2_probs:
|
| 249 |
# Use GPT-2's own contextual predictions
|
| 250 |
gpt2_preds = sorted(gpt2_probs.items(), key=lambda x: x[1], reverse=True)
|
|
|
|
| 251 |
gpt2_preds = filter_suggestions(gpt2_preds)
|
| 252 |
return [w for w, _ in gpt2_preds[:n]]
|
| 253 |
return self._bigram_predict(context, n)
|
|
@@ -256,6 +260,7 @@ class HybridAutoComplete:
|
|
| 256 |
if total == 0:
|
| 257 |
if gpt2_probs:
|
| 258 |
gpt2_preds = sorted(gpt2_probs.items(), key=lambda x: x[1], reverse=True)
|
|
|
|
| 259 |
gpt2_preds = filter_suggestions(gpt2_preds)
|
| 260 |
return [w for w, _ in gpt2_preds[:n]]
|
| 261 |
return self._bigram_predict(context, n)
|
|
@@ -283,6 +288,8 @@ class HybridAutoComplete:
|
|
| 283 |
|
| 284 |
results.sort(key=lambda x: x[1], reverse=True)
|
| 285 |
results = filter_suggestions(results)
|
|
|
|
|
|
|
| 286 |
|
| 287 |
return [w for w, _ in results[:n]]
|
| 288 |
|
|
|
|
| 75 |
self.gpt2_model = None
|
| 76 |
self.device = "cpu"
|
| 77 |
self.alpha = 0.4 # Weight: 40% bigram, 60% GPT-2 (GPT-2 has context!)
|
| 78 |
+
self.threshold = 0.05 # Min score to show a suggestion
|
| 79 |
self._cache = {}
|
| 80 |
self._cache_max = 256
|
| 81 |
|
|
|
|
| 136 |
|
| 137 |
# ─── Prediction ───────────────────────────────────────────────────────
|
| 138 |
|
| 139 |
+
def predict(self, context: str, n: int = 3) -> list:
|
| 140 |
"""
|
| 141 |
Get top-N autocomplete suggestions for the given context.
|
| 142 |
|
|
|
|
| 177 |
logger.error(f"AutoComplete prediction error: {e}")
|
| 178 |
return []
|
| 179 |
|
| 180 |
+
def _bigram_predict(self, context: str, n: int = 3) -> list:
|
| 181 |
"""Statistical-only prediction using bigram model."""
|
| 182 |
from .autocomplete_rules import merge_similar_predictions, filter_suggestions
|
| 183 |
|
|
|
|
| 213 |
preds.sort(key=lambda x: x[1], reverse=True)
|
| 214 |
preds = merge_similar_predictions(preds, top_k=n * 3)
|
| 215 |
preds = filter_suggestions(preds)
|
| 216 |
+
# Apply score threshold
|
| 217 |
+
preds = [(w, s) for w, s in preds if s >= self.threshold]
|
| 218 |
|
| 219 |
return [w for w, _ in preds[:n]]
|
| 220 |
|
| 221 |
+
def _hybrid_predict(self, context: str, n: int = 3) -> list:
|
| 222 |
"""Hybrid prediction: bigram + GPT-2 scoring.
|
| 223 |
|
| 224 |
GPT-2 receives the FULL sentence as context for true context awareness.
|
|
|
|
| 251 |
if gpt2_probs:
|
| 252 |
# Use GPT-2's own contextual predictions
|
| 253 |
gpt2_preds = sorted(gpt2_probs.items(), key=lambda x: x[1], reverse=True)
|
| 254 |
+
gpt2_preds = [(w, s) for w, s in gpt2_preds if s >= self.threshold]
|
| 255 |
gpt2_preds = filter_suggestions(gpt2_preds)
|
| 256 |
return [w for w, _ in gpt2_preds[:n]]
|
| 257 |
return self._bigram_predict(context, n)
|
|
|
|
| 260 |
if total == 0:
|
| 261 |
if gpt2_probs:
|
| 262 |
gpt2_preds = sorted(gpt2_probs.items(), key=lambda x: x[1], reverse=True)
|
| 263 |
+
gpt2_preds = [(w, s) for w, s in gpt2_preds if s >= self.threshold]
|
| 264 |
gpt2_preds = filter_suggestions(gpt2_preds)
|
| 265 |
return [w for w, _ in gpt2_preds[:n]]
|
| 266 |
return self._bigram_predict(context, n)
|
|
|
|
| 288 |
|
| 289 |
results.sort(key=lambda x: x[1], reverse=True)
|
| 290 |
results = filter_suggestions(results)
|
| 291 |
+
# Apply score threshold — filter out low-confidence suggestions
|
| 292 |
+
results = [(w, s) for w, s in results if s >= self.threshold]
|
| 293 |
|
| 294 |
return [w for w, _ in results[:n]]
|
| 295 |
|