Download src/semantic_engine/nlp.py from Snapkitty/semantic-engine: direct link, hf CLI and curl.
- Browser
- Download file 7.23 kB
-
https://huggingface.co/Snapkitty/semantic-engine/resolve/main/src/semantic_engine/nlp.py
- Command line
-
hf download hf://Snapkitty/semantic-engine/src/semantic_engine/nlp.py
-
curl -L -o nlp.py https://huggingface.co/Snapkitty/semantic-engine/resolve/main/src/semantic_engine/nlp.py
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) | |