Skip to content

Commit

Permalink
Merge pull request #103 from vintasoftware/feat/docs-ref
Browse files Browse the repository at this point in the history
Reference documentation
  • Loading branch information
fjsj authored Jun 20, 2024
2 parents a3a1190 + 19b4944 commit 285f862
Show file tree
Hide file tree
Showing 14 changed files with 336 additions and 115 deletions.
20 changes: 14 additions & 6 deletions django_ai_assistant/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
ThreadSchemaIn,
)
from django_ai_assistant.conf import app_settings
from django_ai_assistant.exceptions import AIUserNotAllowedError
from django_ai_assistant.exceptions import AIAssistantNotDefinedError, AIUserNotAllowedError
from django_ai_assistant.helpers import use_cases
from django_ai_assistant.models import Message, Thread

Expand Down Expand Up @@ -52,6 +52,15 @@ def ai_user_not_allowed_handler(request, exc):
)


@api.exception_handler(AIAssistantNotDefinedError)
def ai_assistant_not_defined_handler(request, exc):
return api.create_response(
request,
{"message": str(exc)},
status=404,
)


@api.get("assistants/", response=List[AssistantSchema], url_name="assistants_list")
def list_assistants(request):
return list(use_cases.get_assistants_info(user=request.user, request=request))
Expand All @@ -66,7 +75,7 @@ def get_assistant(request, assistant_id: str):

@api.get("threads/", response=List[ThreadSchema], url_name="threads_list_create")
def list_threads(request):
return list(use_cases.get_threads(user=request.user, request=request))
return list(use_cases.get_threads(user=request.user))


@api.post("threads/", response=ThreadSchema, url_name="threads_list_create")
Expand All @@ -82,7 +91,7 @@ def get_thread(request, thread_id: str):
thread_id=thread_id, user=request.user, request=request
)
except Thread.DoesNotExist:
raise Http404("No %s matches the given query." % Thread._meta.object_name) from None
raise Http404(f"No Thread with id={thread_id} found") from None
return thread


Expand All @@ -106,9 +115,8 @@ def delete_thread(request, thread_id: str):
url_name="messages_list_create",
)
def list_thread_messages(request, thread_id: str):
messages = use_cases.get_thread_messages(
thread_id=thread_id, user=request.user, request=request
)
thread = get_object_or_404(Thread, id=thread_id)
messages = use_cases.get_thread_messages(thread=thread, user=request.user, request=request)
return [message_to_dict(m)["data"] for m in messages]


Expand Down
6 changes: 6 additions & 0 deletions django_ai_assistant/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
class AIAssistantMisconfiguredError(Exception):
"""Raised when the AI assistant is misconfigured, e.g. when assistant id is invalid."""

pass


class AIAssistantNotDefinedError(Exception):
"""Raised when the AI assistant is not defined when trying to get it by id."""

pass


class AIUserNotAllowedError(Exception):
"""Raised when the user has no permission to manage a Thread, Message, or AIAssistant."""

pass
35 changes: 25 additions & 10 deletions django_ai_assistant/helpers/assistants.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,11 @@

class AIAssistant(abc.ABC): # noqa: F821
"""Base class for AI Assistants. Subclasses must define at least the following attributes:
- id: str
- name: str
- instructions: str
- model: str
* id: str
* name: str
* instructions: str
* model: str
Subclasses can override the public methods to customize the behavior of the assistant.\n
Tools can be added to the assistant by decorating methods with `@method_tool`.\n
Expand Down Expand Up @@ -102,15 +103,29 @@ class AIAssistant(abc.ABC): # noqa: F821
Automatically populated by when a subclass is declared.\n
Use `get_cls_registry` and `get_cls` to access the registry."""

def __init__(self, *, user=None, request=None, view=None, **kwargs):
def __init__(self, *, user=None, request=None, view=None, **kwargs: Any):
"""Initialize the AIAssistant instance.\n
Optionally set the current user, request, and view for the assistant.\n
Those can be used in any `@method_tool` to customize behavior.\n
Args:
user (Any | None): The current user the assistant is helping. A model instance.
Defaults to `None`. Stored in `self._user`.
request (Any | None): The current Django request the assistant was initialized with.
A request instance. Defaults to `None`. Stored in `self._request`.
view (Any | None): The current Django view the assistant was initialized with.
A view instance. Defaults to `None`. Stored in `self._view`.
**kwargs: Extra keyword arguments passed to the constructor. Stored in `self._init_kwargs`.
"""

self._user = user
self._request = request
self._view = view
self._init_kwargs = kwargs

self._set_method_tools()

def __init_subclass__(cls, **kwargs):
def __init_subclass__(cls, **kwargs: Any):
"""Called when a class is subclassed from AIAssistant.
This method is automatically invoked when a new subclass of AIAssistant
Expand Down Expand Up @@ -499,7 +514,7 @@ def as_chain(self, thread_id: int | None) -> Runnable[dict, dict]:

return agent_with_chat_history

def invoke(self, *args, thread_id: int | None, **kwargs):
def invoke(self, *args: Any, thread_id: int | None, **kwargs: Any) -> dict:
"""Invoke the assistant Langchain chain with the given arguments and keyword arguments.\n
This is the lower-level method to run the assistant.\n
The chain is created by the `as_chain` method.\n
Expand All @@ -518,7 +533,7 @@ def invoke(self, *args, thread_id: int | None, **kwargs):
chain = self.as_chain(thread_id)
return chain.invoke(*args, **kwargs)

def run(self, message, thread_id: int | None, **kwargs):
def run(self, message: str, thread_id: int | None, **kwargs: Any) -> str:
"""Run the assistant with the given message and thread ID.\n
This is the higher-level method to run the assistant.\n
Expand All @@ -539,10 +554,10 @@ def run(self, message, thread_id: int | None, **kwargs):
**kwargs,
)["output"]

def _run_as_tool(self, message: str, **kwargs):
def _run_as_tool(self, message: str, **kwargs: Any) -> str:
return self.run(message, thread_id=None, **kwargs)

def as_tool(self, description) -> BaseTool:
def as_tool(self, description: str) -> BaseTool:
"""Create a tool from the assistant.\n
This is useful to compose assistants.\n
Expand Down
Loading

0 comments on commit 285f862

Please sign in to comment.