Skip to content

Commit

Permalink
update to use route rather than decision
Browse files Browse the repository at this point in the history
  • Loading branch information
jamescalam committed Dec 12, 2023
1 parent 4a81de1 commit 58af037
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 83 deletions.
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "semantic-router"
version = "0.0.5"
version = "0.0.7"
description = "Super fast semantic router for AI decision making"
authors = [
"James Briggs <[email protected]>",
Expand Down
4 changes: 2 additions & 2 deletions semantic_router/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
from .layer import DecisionLayer, HybridDecisionLayer
from .layer import RouteLayer, HybridRouteLayer

__all__ = ["DecisionLayer", "HybridDecisionLayer"]
__all__ = ["RouteLayer", "HybridRouteLayer"]
92 changes: 46 additions & 46 deletions semantic_router/layer.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@
BM25Encoder,
)
from semantic_router.linear import similarity_matrix, top_scores
from semantic_router.schema import Decision
from semantic_router.schema import Route


class DecisionLayer:
class RouteLayer:
index = None
categories = None
score_threshold = 0.82

def __init__(self, encoder: BaseEncoder, decisions: list[Decision] = []):
def __init__(self, encoder: BaseEncoder, routes: list[Route] = []):
self.encoder = encoder
# decide on default threshold based on encoder
if isinstance(encoder, OpenAIEncoder):
Expand All @@ -26,11 +26,11 @@ def __init__(self, encoder: BaseEncoder, decisions: list[Decision] = []):
self.score_threshold = 0.3
else:
self.score_threshold = 0.82
# if decisions list has been passed, we initialize index now
if decisions:
# if routes list has been passed, we initialize index now
if routes:
# initialize index now
for decision in tqdm(decisions):
self._add_decision(decision=decision)
for route in tqdm(routes):
self._add_route(route=route)

def __call__(self, text: str) -> str | None:
results = self._query(text)
Expand All @@ -41,18 +41,18 @@ def __call__(self, text: str) -> str | None:
else:
return None

def add(self, decision: Decision):
self._add_decision(decision=decision)
def add(self, route: Route):
self._add_route(route=route)

def _add_decision(self, decision: Decision):
def _add_route(self, route: Route):
# create embeddings
embeds = self.encoder(decision.utterances)
embeds = self.encoder(route.utterances)

# create decision array
# create route array
if self.categories is None:
self.categories = np.array([decision.name] * len(embeds))
self.categories = np.array([route.name] * len(embeds))
else:
str_arr = np.array([decision.name] * len(embeds))
str_arr = np.array([route.name] * len(embeds))
self.categories = np.concatenate([self.categories, str_arr])
# create utterance array (the index)
if self.index is None:
Expand All @@ -73,10 +73,10 @@ def _query(self, text: str, top_k: int = 5):
# calculate similarity matrix
sim = similarity_matrix(xq, self.index)
scores, idx = top_scores(sim, top_k)
# get the utterance categories (decision names)
decisions = self.categories[idx] if self.categories is not None else []
# get the utterance categories (route names)
routes = self.categories[idx] if self.categories is not None else []
return [
{"decision": d, "score": s.item()} for d, s in zip(decisions, scores)
{"route": d, "score": s.item()} for d, s in zip(routes, scores)
]
else:
return []
Expand All @@ -85,15 +85,15 @@ def _semantic_classify(self, query_results: list[dict]) -> tuple[str, list[float
scores_by_class = {}
for result in query_results:
score = result["score"]
decision = result["decision"]
if decision in scores_by_class:
scores_by_class[decision].append(score)
route = result["route"]
if route in scores_by_class:
scores_by_class[route].append(score)
else:
scores_by_class[decision] = [score]
scores_by_class[route] = [score]

# Calculate total score for each class
total_scores = {
decision: sum(scores) for decision, scores in scores_by_class.items()
route: sum(scores) for route, scores in scores_by_class.items()
}
top_class = max(total_scores, key=lambda x: total_scores[x], default=None)

Expand All @@ -107,14 +107,14 @@ def _pass_threshold(self, scores: list[float], threshold: float) -> bool:
return False


class HybridDecisionLayer:
class HybridRouteLayer:
index = None
sparse_index = None
categories = None
score_threshold = 0.82

def __init__(
self, encoder: BaseEncoder, decisions: list[Decision] = [], alpha: float = 0.3
self, encoder: BaseEncoder, routes: list[Route] = [], alpha: float = 0.3
):
self.encoder = encoder
self.sparse_encoder = BM25Encoder()
Expand All @@ -126,11 +126,11 @@ def __init__(
self.score_threshold = 0.3
else:
self.score_threshold = 0.82
# if decisions list has been passed, we initialize index now
if decisions:
# if routes list has been passed, we initialize index now
if routes:
# initialize index now
for decision in tqdm(decisions):
self._add_decision(decision=decision)
for route in tqdm(routes):
self._add_route(route=route)

def __call__(self, text: str) -> str | None:
results = self._query(text)
Expand All @@ -141,25 +141,25 @@ def __call__(self, text: str) -> str | None:
else:
return None

def add(self, decision: Decision):
self._add_decision(decision=decision)
def add(self, route: Route):
self._add_route(route=route)

def _add_decision(self, decision: Decision):
def _add_route(self, route: Route):
# create embeddings
dense_embeds = np.array(self.encoder(decision.utterances)) # * self.alpha
dense_embeds = np.array(self.encoder(route.utterances)) # * self.alpha
sparse_embeds = np.array(
self.sparse_encoder(decision.utterances)
self.sparse_encoder(route.utterances)
) # * (1 - self.alpha)

# create decision array
# create route array
if self.categories is None:
self.categories = np.array([decision.name] * len(decision.utterances))
self.utterances = np.array(decision.utterances)
self.categories = np.array([route.name] * len(route.utterances))
self.utterances = np.array(route.utterances)
else:
str_arr = np.array([decision.name] * len(decision.utterances))
str_arr = np.array([route.name] * len(route.utterances))
self.categories = np.concatenate([self.categories, str_arr])
self.utterances = np.concatenate(
[self.utterances, np.array(decision.utterances)]
[self.utterances, np.array(route.utterances)]
)
# create utterance array (the dense index)
if self.index is None:
Expand Down Expand Up @@ -199,10 +199,10 @@ def _query(self, text: str, top_k: int = 5):
top_k = min(top_k, total_sim.shape[0])
idx = np.argpartition(total_sim, -top_k)[-top_k:]
scores = total_sim[idx]
# get the utterance categories (decision names)
decisions = self.categories[idx] if self.categories is not None else []
# get the utterance categories (route names)
routes = self.categories[idx] if self.categories is not None else []
return [
{"decision": d, "score": s.item()} for d, s in zip(decisions, scores)
{"route": d, "score": s.item()} for d, s in zip(routes, scores)
]
else:
return []
Expand All @@ -217,15 +217,15 @@ def _semantic_classify(self, query_results: list[dict]) -> tuple[str, list[float
scores_by_class = {}
for result in query_results:
score = result["score"]
decision = result["decision"]
if decision in scores_by_class:
scores_by_class[decision].append(score)
route = result["route"]
if route in scores_by_class:
scores_by_class[route].append(score)
else:
scores_by_class[decision] = [score]
scores_by_class[route] = [score]

# Calculate total score for each class
total_scores = {
decision: sum(scores) for decision, scores in scores_by_class.items()
route: sum(scores) for route, scores in scores_by_class.items()
}
top_class = max(total_scores, key=lambda x: total_scores[x], default=None)

Expand Down
12 changes: 6 additions & 6 deletions semantic_router/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
)


class Decision(BaseModel):
class Route(BaseModel):
name: str
utterances: list[str]
description: str | None = None
Expand Down Expand Up @@ -45,12 +45,12 @@ def __call__(self, texts: list[str]) -> list[float]:
@dataclass
class SemanticSpace:
id: str
decisions: list[Decision]
routes: list[Route]
encoder: str = ""

def __init__(self, decisions: list[Decision] = []):
def __init__(self, routes: list[Route] = []):
self.id = ""
self.decisions = decisions
self.routes = routes

def add(self, decision: Decision):
self.decisions.append(decision)
def add(self, route: Route):
self.routes.append(route)
Loading

0 comments on commit 58af037

Please sign in to comment.