SNAPKITTYWEST's picture
October 2026 main drop: mirror from GitHub
fc3e70a verified
Raw History Blame Contribute Delete
7.23 kB
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
"""NLP subsystem β€” tokenization, entity extraction, intent classification, BERT interface.
BERT operates as an internal interpretive tool only. Output is SemanticCandidate,
never executable code. The FSM remains the admissibility gate.
"""
from __future__ import annotations
import re
from dataclasses import dataclass, field
from typing import Optional
from .types import IntentClass, NormalizedInput, RawInput, SemanticCandidate
# ── Controlled vocabulary for intent ─────────────────────────────────────────
_INTENT_PATTERNS: list[tuple[IntentClass, list[str]]] = [
(IntentClass.BUILD, ["build", "create", "make", "construct", "implement", "write"]),
(IntentClass.TRANSFORM, ["transform", "convert", "translate", "map", "rewrite", "change"]),
(IntentClass.VALIDATE, ["validate", "verify", "check", "confirm", "ensure", "test"]),
(IntentClass.GENERATE, ["generate", "produce", "emit", "output", "render"]),
(IntentClass.PARSE, ["parse", "read", "decode", "lex", "scan", "interpret"]),
(IntentClass.COMPUTE, ["compute", "calculate", "multiply", "add", "subtract", "solve"]),
(IntentClass.RECONSTRUCT, ["reconstruct", "restore", "recover", "rebuild", "regenerate"]),
]
_OPERATOR_PATTERNS = re.compile(
r"\b(multiply|add|subtract|divide|transform|convert|validate|parse|build|generate|"
r"compute|verify|reconstruct|normalize|encode|decode|serialize|deserialize)\b",
re.IGNORECASE,
)
_ENTITY_PATTERNS = re.compile(
r"\b(matrix|vector|parser|backend|service|function|module|component|token|"
r"format|stream|buffer|table|schema|graph|tree|list|array|string|integer|"
r"boolean|packet|message|frame|field|register)\b",
re.IGNORECASE,
)
_CONSTRAINT_PATTERNS = re.compile(
r"\b(deterministic|immutable|idempotent|commutative|associative|invertible|"
r"ordered|typed|bounded|validated|correct|minimal|canonical|stable)\b",
re.IGNORECASE,
)
_RELATIONSHIP_PATTERN = re.compile(
r"(\w+)\s+(of|from|to|into|for|with|by|through|via|as)\s+(\w+)",
re.IGNORECASE,
)
# ── Tokenizer ─────────────────────────────────────────────────────────────────
def tokenize(text: str) -> list[str]:
return re.findall(r"\w+|[^\w\s]", text)
def segment_sentences(text: str) -> list[str]:
return [s.strip() for s in re.split(r"(?<=[.!?])\s+", text) if s.strip()]
# ── Rule-based NLP (no external model required) ───────────────────────────────
def classify_intent(text: str) -> tuple[IntentClass, float]:
lower = text.lower()
scores: dict[IntentClass, int] = {}
for intent, keywords in _INTENT_PATTERNS:
for kw in keywords:
if kw in lower:
scores[intent] = scores.get(intent, 0) + 1
if not scores:
return IntentClass.UNKNOWN, 0.3
best = max(scores, key=lambda k: scores[k])
confidence = min(0.5 + scores[best] * 0.15, 0.95)
return best, confidence
def extract_entities(text: str) -> list[str]:
return list({m.group(0).lower() for m in _ENTITY_PATTERNS.finditer(text)})
def extract_operators(text: str) -> list[str]:
return list({m.group(0).lower() for m in _OPERATOR_PATTERNS.finditer(text)})
def extract_constraints(text: str) -> list[str]:
return list({m.group(0).lower() for m in _CONSTRAINT_PATTERNS.finditer(text)})
def extract_relationships(text: str) -> list[tuple[str, str, str]]:
return [(m.group(1).lower(), m.group(2).lower(), m.group(3).lower())
for m in _RELATIONSHIP_PATTERN.finditer(text)]
def detect_ambiguity(text: str) -> bool:
ambiguous_markers = re.compile(
r"\b(it|this|that|they|something|somehow|maybe|perhaps|possibly|"
r"or something|etc|and so on)\b",
re.IGNORECASE,
)
return bool(ambiguous_markers.search(text))
# ── BERT interface ────────────────────────────────────────────────────────────
class BertDecoder:
"""
Internal BERT interface for semantic interpretation.
If the `transformers` package is available and a model is configured,
uses real BERT embeddings. Otherwise falls back to rule-based analysis.
BERT output is always SemanticCandidate β€” never executable code.
The FSM is the admissibility gate regardless of BERT confidence.
"""
def __init__(self, model_name: Optional[str] = None):
self._model = None
self._tokenizer = None
self._use_bert = False
if model_name:
try:
from transformers import AutoModel, AutoTokenizer # type: ignore
import torch # type: ignore
self._tokenizer = AutoTokenizer.from_pretrained(model_name)
self._model = AutoModel.from_pretrained(model_name)
self._torch = torch
self._use_bert = True
except ImportError:
pass # fall back to rule-based
def _bert_embeddings(self, text: str) -> Optional[list[float]]:
if not self._use_bert:
return None
inputs = self._tokenizer(text, return_tensors="pt", truncation=True, max_length=512)
with self._torch.no_grad():
outputs = self._model(**inputs)
cls_embedding = outputs.last_hidden_state[:, 0, :].squeeze().tolist()
return cls_embedding if isinstance(cls_embedding, list) else [cls_embedding]
def decode(self, normalized: NormalizedInput) -> SemanticCandidate:
text = normalized.text
intent, confidence = classify_intent(text)
entities = extract_entities(text)
operators = extract_operators(text)
constraints = extract_constraints(text)
rels = extract_relationships(text)
ambiguous = detect_ambiguity(text)
embeddings = self._bert_embeddings(text)
return SemanticCandidate(
input_ref=normalized.original.input_id,
intent=intent,
entities=entities,
operators=operators,
constraints=constraints,
relationships=rels,
confidence=confidence,
ambiguous=ambiguous,
raw_embeddings=embeddings,
)
# ── Input normalization ───────────────────────────────────────────────────────
def normalize_input(raw: RawInput) -> NormalizedInput:
text = raw.text.strip()
text = re.sub(r"\s+", " ", text)
tokens = tuple(tokenize(text))
sentences = tuple(segment_sentences(text))
return NormalizedInput(original=raw, text=text, tokens=tokens, sentences=sentences)