Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unit tests and change some names #2

Merged
merged 13 commits into from
Sep 22, 2024
6 changes: 0 additions & 6 deletions .github/.pre-commit-config.yaml

This file was deleted.

42 changes: 42 additions & 0 deletions .github/workflows/black.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Black Formatter

on:
pull_request:
branches:
- main

jobs:
format:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install black

- name: Run Black formatter
id: black
run: black .

- name: Commit and push changes
run: |
git config --local user.name "GitHub Actions"
git config --local user.email "[email protected]"
git add .
# Check if there are any changes to commit
if ! git diff --cached --quiet; then
git commit -m "Apply Black formatting"
git push
else
echo "No changes to commit"
fi
if: ${{ steps.black.outcome == 'success' }}
2 changes: 1 addition & 1 deletion memonto/core/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from memonto.stores.base_store import StoreModel


def query_memory_data(store: StoreModel, id: str, uri: URIRef, query: str) -> None:
def query_memory_store(store: StoreModel, id: str, uri: URIRef, query: str) -> None:
if query:
return store.get_raw(query=query)
else:
Expand Down
2 changes: 1 addition & 1 deletion memonto/core/load.py → memonto/core/remember.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
from memonto.stores.base_store import StoreModel


def load_memory(store: StoreModel, id: str = None, debug: bool = False) -> Graph:
def load_memory(store: StoreModel, id: str, debug: bool) -> Graph:
return store.load(id=id, debug=debug)
File renamed without changes.
8 changes: 4 additions & 4 deletions memonto/core/commit.py → memonto/core/retain.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,13 @@ def commit_memory(
llm: LLMModel,
store: StoreModel,
query: str,
id: str = None,
debug: bool = False,
expand_ontology: bool = True,
id: str,
auto_expand: bool,
debug: bool,
) -> None:
gt = g.serialize(format="turtle")

if expand_ontology:
if auto_expand:
instruction = "- If there are information that is valuable but doesn't fit onto the ontology then add them as well."
temperature = 0.5
else:
Expand Down
File renamed without changes.
15 changes: 9 additions & 6 deletions memonto/llms/base_llm.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import tiktoken
from abc import ABC, abstractmethod
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict

from memonto.utils.llm import load_prompt

Expand All @@ -12,6 +12,7 @@ class LLMModel(BaseModel, ABC):
context_windows: dict = ...
temperature: float = ...
client: object = None
model_config = ConfigDict(arbitrary_types_allowed=True)

@abstractmethod
def prompt(
Expand Down Expand Up @@ -45,7 +46,12 @@ def _get_context_window(self, default: int = 32_000) -> int:

return default

def _fit_to_context_window(self, prompt_name: str, encoding_model: str = "cl100k_base", **kwargs) -> str:
def _fit_to_context_window(
self,
prompt_name: str,
encoding_model: str = "cl100k_base",
**kwargs,
) -> str:
"""
Render the a prompt template with the given keyword arguments and fit it to the model's context window.
Prompts are truncated based on the order they are based in.
Expand All @@ -62,7 +68,7 @@ def _fit_to_context_window(self, prompt_name: str, encoding_model: str = "cl100k
encoding = tiktoken.encoding_for_model(encoding_model)
except Exception:
encoding = tiktoken.get_encoding(encoding_model)

max_tokens = self._get_context_window()
buffer = 0.2

Expand All @@ -86,6 +92,3 @@ def _fit_to_context_window(self, prompt_name: str, encoding_model: str = "cl100k
break

return prompt_template.substitute(**truncated_kwargs)

class Config:
arbitrary_types_allowed = True
81 changes: 44 additions & 37 deletions memonto/memonto.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
from pydantic import BaseModel, Field, model_validator
from pydantic import BaseModel, ConfigDict, Field
from rdflib import Graph, Namespace, URIRef
from typing import Optional, Union

from memonto.core.commit import commit_memory
from memonto.core.retain import commit_memory
from memonto.core.configure import configure
from memonto.core.fetch import fetch_memory
from memonto.core.graph import render_memory
from memonto.core.load import load_memory
from memonto.core.query import query_memory_data
from memonto.core.retrieve import fetch_memory
from memonto.core.render import render_memory
from memonto.core.remember import load_memory
from memonto.core.query import query_memory_store
from memonto.llms.base_llm import LLMModel
from memonto.stores.base_store import StoreModel


class Memonto(BaseModel):
g: Graph = Field(
...,
description="An RDF graph representing the ontology of the memory.",
g: Graph = Field(..., description="An RDF graph representation of memories.")
# TODO: support multiple namespaces
n: Namespace = Field(..., description="Am RDF namespace for the memory.")
llm: Optional[LLMModel] = Field(None, description="LLM model instance.")
store: Optional[StoreModel] = Field(None, description="Datastore instance.")
debug: Optional[bool] = Field(False, description="Enable debug mode.")
auto_expand: Optional[bool] = Field(
False, description="Enable automatic expansion of the ontology."
)
n: Namespace = Field(
...,
description="A namespace for the memory ontology.",
)
llm: Optional[LLMModel] = Field(None, description="Model instance.")
store: Optional[StoreModel] = Field(None, description="Store instance.")
debug: Optional[bool] = Field(False, description="Flag to enable debug mode.")
expand_ontology: Optional[bool] = Field(
False,
description="Flag to enable automatic expansion of the ontology.",
auto_forget: Optional[bool] = Field(
False, description="Enable automatic forgetting of memories."
)
model_config = ConfigDict(arbitrary_types_allowed=True)

def configure(self, config: dict) -> None:
"""
Expand Down Expand Up @@ -56,12 +54,12 @@ def configure(self, config: dict) -> None:
"""
return configure(self, config=config)

def commit(self, query: str, id: str = None) -> None:
def retain(self, query: str, id: str = None) -> None:
"""
Break down the user's query for relevant information that maps onto an RDF ontology and store them as memories.
Analyze a text for relevant information that maps onto an RDF ontology then commit them to the memory store.

:param query: The user query that is broken down into a graph then committed to memory.
:param id[Optional]: Identifier to track the memory associated with a unique transaction or user.
:param id[Optional]: Unique identifier for a memory. Often associated with a unique transaction or user.

:return: None
"""
Expand All @@ -73,56 +71,65 @@ def commit(self, query: str, id: str = None) -> None:
query=query,
id=id,
debug=self.debug,
expand_ontology=self.expand_ontology,
auto_expand=self.auto_expand,
)

def load(self, id: str = None) -> None:
def remember(self, id: str = None) -> None:
"""
Load existing memory from the store.
Load existing memories from the memory store to a memonto instance.

:param id[Optional]: Identifier to load the memory associated with a unique transaction or user.
:param id[Optional]: Unique identifier for a memory. Often associated with a unique transaction or user.

:return: None.
"""
self.g = load_memory(store=self.store, id=id)

def fetch(self) -> str:
def retrieve(self) -> str:
"""
Return a text summary of the current memory.
Return a text summary of all memories currently stored in the memory store.

:return: A text summary of the current memory.
:return: A text summary of the entire current memory.
"""
return fetch_memory(g=self.g, llm=self.llm)

def recall(self):
"""
Return a text summary of partial memories that are relevant to a context.
"""
pass

def forget(self):
"""
Remove memories from the memory store.
"""
pass

def query(self, id: str = None, uri: URIRef = None, query: str = None) -> list:
"""
Perform query against the datastore to retrieve raw memory data rather than a summary.
Perform query against the memory store to retrieve raw memory data rather than a summary.

:param id[Optional]: Identifier to track the memory associated with a unique transaction or user.
:param id[Optional]: Unique identifier for a memory. Often associated with a unique transaction or user.
:param uri[Optional]: URI of the entity to query for.
:param query[Optional]: Raw query that will be performed against the datastore. If you pass in a raw query then the id and uri parameters will be ignored.

:return: A list of triples (subject, predicate, object).
"""
return query_memory_data(store=self.store, id=id, uri=uri, query=query)
return query_memory_store(store=self.store, id=id, uri=uri, query=query)

def render(self, format: str = "turtle") -> Union[str, dict]:
"""
Return a text representation of the memory ontology.
Return a text representation of the entire currently stored memory.

:param format: The format in which to render the graph. Supported formats are:
- "turtle": Return the graph in Turtle format.
- "json": Return the graph in JSON-LD format.
- "text": Return the graph in text format.
- "image": Return the graph as a png image.

:return: A text representation of the memory ontology.
:return: A text representation of the memory.
- "turtle" format returns a string in Turtle format.
- "json" format returns a dictionary in JSON-LD format.
- "text" format returns a string in text format.
- "image" format returns a string with the path to the png image.
"""
return render_memory(g=self.g, format=format)

class Config:
arbitrary_types_allowed = True
6 changes: 2 additions & 4 deletions memonto/stores/base_store.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
from abc import ABC, abstractmethod
from pydantic import BaseModel
from pydantic import BaseModel, ConfigDict


class StoreModel(BaseModel, ABC):
name: str = ...
model_config = ConfigDict(arbitrary_types_allowed=True)

@abstractmethod
def save(self) -> None:
Expand All @@ -25,6 +26,3 @@ def get(self) -> None:
Perform a get query against the datastore for memory data.
"""
pass

class Config:
arbitrary_types_allowed = True
Empty file added tests/core/__init__.py
Empty file.
Loading
Loading