diff --git a/anansyTypes/__init__.py b/anansyTypes/__init__.py index 2284128..9d7a407 100644 --- a/anansyTypes/__init__.py +++ b/anansyTypes/__init__.py @@ -1,6 +1,6 @@ from .enums import * from .schemas import * -from .structures import Embedding, Word, Symbol, Phrase,Lexeme,NoEmbeddingPhrase +from .structures import Embedding, Word, Symbol, Phrase,Lexeme __all__ = [ @@ -11,7 +11,6 @@ __all__ = [ "Symbol", "Phrase", "Lexeme", - "NoEmbeddingPhrase", "EmbedRequest", "EmbeddingResponse", "ResponseRequest", @@ -28,6 +27,8 @@ __all__ = [ "SymbolProvider", "Language", "DiscountType", + "Currency", + "SubscriptionType" ] diff --git a/anansyTypes/schemas.py b/anansyTypes/schemas.py index 0457c34..0050e55 100644 --- a/anansyTypes/schemas.py +++ b/anansyTypes/schemas.py @@ -2,7 +2,7 @@ from pydantic import BaseModel as PydanticBaseModel from typing import List, Any, Dict, Optional,Union -from .structures import Embedding,Word, Symbol,Phrase,NoEmbeddingPhrase +from .structures import Embedding,Word, Symbol,Phrase from pydantic import field_validator, ConfigDict from pydantic_tensor import Tensor import torch @@ -50,10 +50,10 @@ class GetSimilarWordRequest(ModifiedBaseModel): embedding: Embedding class GetAllPhrasesResponse(ModifiedBaseModel): - phrases: Optional[List[NoEmbeddingPhrase]] + phrases: Optional[List[Phrase]] class GetFullPhrasesRequest(ModifiedBaseModel): - phrases: List[NoEmbeddingPhrase] + phrases: List[Phrase] class GetFullPhrasesResponse(ModifiedBaseModel): phrases: Optional[List[Phrase]] diff --git a/anansyTypes/structures/__init__.py b/anansyTypes/structures/__init__.py index 22bf775..7ac324a 100644 --- a/anansyTypes/structures/__init__.py +++ b/anansyTypes/structures/__init__.py @@ -2,7 +2,7 @@ from .embedding import Embedding from .lexeme import Lexeme from .word import Word from .symbol import Symbol -from .phrase import Phrase,NoEmbeddingPhrase +from .phrase import Phrase __all__ = [ @@ -11,5 +11,4 @@ __all__ = [ "Word", "Symbol", "Phrase", - "NoEmbeddingPhrase", ] diff --git a/anansyTypes/structures/embedding.py b/anansyTypes/structures/embedding.py index 50d3809..b396863 100644 --- a/anansyTypes/structures/embedding.py +++ b/anansyTypes/structures/embedding.py @@ -1,55 +1,37 @@ -from __future__ import annotations -from dataclasses import dataclass -import numpy as np -from pydantic_tensor import Tensor +from typing import Any import torch -from typing import Any, Literal - - -@dataclass(frozen=True) -class Embedding: - data: Tensor[torch.Tensor | np.ndarray[Any], tuple, Literal["int64"]] - - def compare(self, other: Embedding) -> float: - """ - Compare this embedding with another embedding. - """ - if isinstance(self.data, np.ndarray) and isinstance(other.data, np.ndarray): - # Simple example: L2 distance (Euclidean distance) - return np.linalg.norm(self.data - other.data) - - # Fallback or error if not implemented for other types (e.g., torch.Tensor) - raise NotImplementedError( - "Comparison must be implemented for all supported data types." - ) +from pydantic import BaseModel +from pydantic_core import core_schema +from typing_extensions import Annotated +import numpy as np +class TensorPydantic: @classmethod - def from_dict(cls, data: dict) -> "Embedding": - return cls(data=np.array(data["data"], dtype=np.float32)) + def __get_pydantic_core_schema__(cls, source, handler): + def validate(v: Any): + if isinstance(v, torch.Tensor): + return v + if isinstance(v, list): + return torch.tensor(v, dtype=torch.float32) + raise TypeError(f"Cannot convert {type(v)} to torch.Tensor") - @classmethod - def __get_pydantic_core_schema__(cls, source_type: Any, handler): - from pydantic_core import core_schema - - def validate_embedding(value): - if isinstance(value, cls): - return value - if isinstance(value, dict): - return cls.from_dict(value) - raise ValueError(f"Cannot convert {type(value)} to Embedding") - - python_schema = core_schema.with_info_plain_validator_function( - lambda value, _: validate_embedding(value), + return core_schema.json_or_python_schema( + json_schema=core_schema.list_schema(core_schema.any_schema()), + python_schema=core_schema.no_info_plain_validator_function(validate), serialization=core_schema.plain_serializer_function_ser_schema( - lambda x: {"data": x.data.tolist()}, - when_used="json", + lambda t: t.detach().cpu().tolist() ), ) - - return core_schema.json_or_python_schema( - json_schema=core_schema.typed_dict_schema({ - 'data': core_schema.typed_dict_field(core_schema.list_schema()) - }), - python_schema=python_schema, - ) + +Tensor = Annotated[torch.Tensor, TensorPydantic] + + +class Embedding(BaseModel): + data: Tensor + + @classmethod + def from_dict(cls, data: dict) -> "Embedding": + return cls(data=torch.tensor(data["data"], dtype=torch.float32)) + + \ No newline at end of file diff --git a/anansyTypes/structures/lexeme.py b/anansyTypes/structures/lexeme.py index ee54362..f460b33 100644 --- a/anansyTypes/structures/lexeme.py +++ b/anansyTypes/structures/lexeme.py @@ -1,71 +1,26 @@ from abc import ABC, abstractmethod from typing import List, Union, Any from dataclasses import dataclass + +from pydantic import BaseModel from .embedding import Embedding - -@dataclass -class Lexeme(ABC): +class Lexeme(BaseModel,ABC): id: int - - @property - @abstractmethod - def content(self) -> Union[str, List[str]]: - """Text content of the lexeme.""" - pass + content: Union[str, List[str]] + original_content: Union[str, List[str]] + embedding: Embedding - @property - @abstractmethod - def original_content(self) -> Union[str, List[str]]: - """Original text content of the lexeme.""" - pass - - @property - @abstractmethod - def embedding(self) -> Embedding: - """Embedding(s) associated with the lexeme.""" - pass @classmethod - @abstractmethod def from_dict(cls, data: dict) -> "Lexeme": - """Create instance from dictionary.""" - pass - - @classmethod - def __get_pydantic_core_schema__(cls, source_type: Any, handler): - from pydantic_core import core_schema - - def validate_lexeme(value): - if isinstance(value, cls): - return value - if isinstance(value, dict): - return cls.from_dict(value) - raise ValueError(f"Cannot convert {type(value)} to {cls.__name__}") - - python_schema = core_schema.with_info_plain_validator_function( - lambda value, _: validate_lexeme(value), - serialization=core_schema.plain_serializer_function_ser_schema( - lambda x: { - "id": x.id, - "content": x.content, - "original_content": x.original_content, - "embedding": {"data": x.embedding.data.tolist()}, - }, - when_used="json", - ), - ) - - return core_schema.json_or_python_schema( - json_schema=core_schema.typed_dict_schema( - { - "id": core_schema.typed_dict_field(core_schema.int_schema()), - "original_content": core_schema.typed_dict_field(core_schema.str_schema()), - "content": core_schema.typed_dict_field(core_schema.str_schema()), - "embedding": core_schema.typed_dict_field( - handler.generate_schema(Embedding) - ), - } - ), - python_schema=python_schema, - ) + return cls( + id=data["id"], + content=data["content"], + embedding=Embedding.from_dict(data["embedding"]), + original_content=data["original_content"], + ) + def __new__(cls, *args, **kwargs): + if cls is Lexeme: + raise TypeError("Lexeme cannot be instantiated, use a subclass instead") + return super().__new__(cls) \ No newline at end of file diff --git a/anansyTypes/structures/phrase.py b/anansyTypes/structures/phrase.py index e1403e2..bb4333f 100644 --- a/anansyTypes/structures/phrase.py +++ b/anansyTypes/structures/phrase.py @@ -1,70 +1,20 @@ from typing import List, Any +from pydantic import model_validator from pydantic_core import core_schema +import torch from .lexeme import Lexeme from .embedding import Embedding import numpy as np -class NoEmbeddingPhrase(Lexeme): - def __init__(self, id: int, content: str): - self.id = id - self._content = content - self._original_content = content - self._embedding = np.array([]) # Placeholder to avoid attribute errors - - @property - def content(self) -> str: - return self._content - - @property - def original_content(self) -> str: - #temporarily return content as original_content - return self._content - - @property - def embedding(self) -> Embedding: - return self._embedding - - @classmethod - def from_dict(cls, data: dict) -> "NoEmbeddingPhrase": - return cls(id=data["id"], content=data["content"]) - - class Phrase(Lexeme): - def __init__(self, id: int, content: str, embedding: Embedding): - self.id = id - self._content = content - self._original_content = content - self._embedding = embedding - - @property - def content(self) -> str: - return self._content - - @property - def original_content(self) -> str: - #temporarily return content as original_content - return self._content - - @property - def embedding(self) -> Embedding: - return self._embedding @classmethod def from_dict(cls, data: dict) -> "Phrase": return cls( id=data["id"], content=data["content"], + original_content=data["original_content"], embedding=Embedding.from_dict(data["embedding"]), ) - - @classmethod - def from_noembeddingphrase( - cls, phrase: NoEmbeddingPhrase, embedding: Embedding - ) -> "Phrase": - return cls( - id=phrase.id, - content=phrase.content, - embedding=embedding, - ) diff --git a/anansyTypes/structures/symbol.py b/anansyTypes/structures/symbol.py index fa211f9..28d7e44 100644 --- a/anansyTypes/structures/symbol.py +++ b/anansyTypes/structures/symbol.py @@ -1,61 +1,22 @@ from dataclasses import dataclass from typing import Any import numpy as np +from pydantic import BaseModel from pydantic_tensor import Tensor from typing import Any, Literal from pydantic_core import core_schema import base64 -@dataclass -class Symbol: +class Symbol(BaseModel): id: int label: str - image: bytes + image: str # Base64-encoded PNG image data @classmethod def from_dict(cls, data: dict) -> "Symbol": - if isinstance(data["image"], str): - image_bytes = base64.b64decode(data["image"]) - else: - image_bytes = bytes(data["image"]) - return cls( id=data["id"], label=data["label"], - image=image_bytes, - ) - - @classmethod - def __get_pydantic_core_schema__(cls, source_type: Any, handler): - from pydantic_core import core_schema - - def validate_symbol(value): - if isinstance(value, cls): - return value - if isinstance(value, dict): - return cls.from_dict(value) - raise ValueError(f"Cannot convert {type(value)} to Symbol") - - python_schema = core_schema.with_info_plain_validator_function( - lambda value, _: validate_symbol(value), - serialization=core_schema.plain_serializer_function_ser_schema( - lambda x: { - "id": x.id, - "label": x.label, - "image": base64.b64encode(x.image).decode("utf-8"), - }, - when_used="json", - ), - ) - - return core_schema.json_or_python_schema( - json_schema=core_schema.typed_dict_schema( - { - "id": core_schema.typed_dict_field(core_schema.int_schema()), - "label": core_schema.typed_dict_field(core_schema.str_schema()), - "image": core_schema.typed_dict_field(core_schema.str_schema()), - } - ), - python_schema=python_schema, - ) + image=data["image"], + ) \ No newline at end of file diff --git a/anansyTypes/structures/word.py b/anansyTypes/structures/word.py index cf998c9..b4dc073 100644 --- a/anansyTypes/structures/word.py +++ b/anansyTypes/structures/word.py @@ -5,34 +5,4 @@ from pydantic_core import core_schema class Word(Lexeme): - def __init__(self, word_id: int, content: str,original_content: str, embedding: Embedding): - self.id = word_id - self._content = content - self._original_content = original_content - self._embedding = embedding - - @property - def content(self) -> str: - return self._content - - @property - def original_content(self) -> str: - return self._original_content - @property - def embedding(self) -> Embedding: - return self._embedding - - def __str__(self): - return self.content - - def __repr__(self): - return self.__str__() - - @classmethod - def from_dict(cls, data: dict) -> "Word": - return cls( - word_id=data["id"], - content=data["content"], - embedding=Embedding.from_dict(data["embedding"]), - original_content=data["original_content"], - ) + pass \ No newline at end of file