Skip to content

Commit

Permalink
Merge branch 'main' into exp/drop-register-decorator
Browse files Browse the repository at this point in the history
  • Loading branch information
pamella committed Jun 19, 2024
2 parents 190ce53 + d4b05f3 commit 9c2df83
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 25 deletions.
10 changes: 9 additions & 1 deletion django_ai_assistant/api/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from langchain_core.messages import message_to_dict
from ninja import NinjaAPI
from ninja.operation import Operation
from ninja.security import django_auth

from django_ai_assistant import package_name, version
from django_ai_assistant.api.schemas import (
Expand All @@ -26,7 +27,14 @@ def get_openapi_operation_id(self, operation: Operation) -> str:
return (package_name + "_" + name).replace(".", "_")


api = API(title=package_name, version=version, urls_namespace="django_ai_assistant")
api = API(
title=package_name,
version=version,
urls_namespace="django_ai_assistant",
# Add auth to all endpoints
auth=django_auth,
csrf=True,
)


@api.exception_handler(AIUserNotAllowedError)
Expand Down
7 changes: 1 addition & 6 deletions example/assets/js/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,7 @@ function ChatMessageList({
deleteMessage,
}: {
messages: ThreadMessagesSchemaOut[];
deleteMessage: ({
threadId,
messageId,
}: {
messageId: string;
}) => Promise<void>;
deleteMessage: ({ messageId }: { messageId: string }) => Promise<void>;
}) {
if (messages.length === 0) {
return <Text c="dimmed">No messages.</Text>;
Expand Down
77 changes: 67 additions & 10 deletions frontend/openapi_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,12 @@
}
}
}
}
},
"security": [
{
"SessionAuth": []
}
]
}
},
"/assistants/{assistant_id}/": {
Expand Down Expand Up @@ -55,7 +60,12 @@
}
}
}
}
},
"security": [
{
"SessionAuth": []
}
]
}
},
"/threads/": {
Expand All @@ -78,7 +88,12 @@
}
}
}
}
},
"security": [
{
"SessionAuth": []
}
]
},
"post": {
"operationId": "django_ai_assistant_create_thread",
Expand All @@ -105,7 +120,12 @@
}
},
"required": true
}
},
"security": [
{
"SessionAuth": []
}
]
}
},
"/threads/{thread_id}/": {
Expand Down Expand Up @@ -134,7 +154,12 @@
}
}
}
}
},
"security": [
{
"SessionAuth": []
}
]
},
"patch": {
"operationId": "django_ai_assistant_update_thread",
Expand Down Expand Up @@ -171,7 +196,12 @@
}
},
"required": true
}
},
"security": [
{
"SessionAuth": []
}
]
},
"delete": {
"operationId": "django_ai_assistant_delete_thread",
Expand All @@ -191,7 +221,12 @@
"204": {
"description": "No Content"
}
}
},
"security": [
{
"SessionAuth": []
}
]
}
},
"/threads/{thread_id}/messages/": {
Expand Down Expand Up @@ -224,7 +259,12 @@
}
}
}
}
},
"security": [
{
"SessionAuth": []
}
]
},
"post": {
"operationId": "django_ai_assistant_create_thread_message",
Expand Down Expand Up @@ -254,7 +294,12 @@
}
},
"required": true
}
},
"security": [
{
"SessionAuth": []
}
]
}
},
"/threads/{thread_id}/messages/{message_id}/": {
Expand Down Expand Up @@ -285,7 +330,12 @@
"204": {
"description": "No Content"
}
}
},
"security": [
{
"SessionAuth": []
}
]
}
}
},
Expand Down Expand Up @@ -414,6 +464,13 @@
"title": "ThreadMessagesSchemaIn",
"type": "object"
}
},
"securitySchemes": {
"SessionAuth": {
"type": "apiKey",
"in": "cookie",
"name": "sessionid"
}
}
},
"servers": []
Expand Down
18 changes: 17 additions & 1 deletion frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@
"generate-client": "openapi-ts"
},
"dependencies": {
"axios": "^1.7.2"
"axios": "^1.7.2",
"cookie": "^0.6.0"
},
"peerDependencies": {
"react": "^18.3.1",
Expand All @@ -52,6 +53,7 @@
"@hey-api/openapi-ts": "^0.46.3",
"@testing-library/dom": "^10.1.0",
"@testing-library/react": "^16.0.0",
"@types/cookie": "^0.6.0",
"@types/jest": "^29.5.12",
"@types/node": "^20.14.1",
"@types/react": "^18.3.3",
Expand Down
13 changes: 13 additions & 0 deletions frontend/src/config.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
import cookie from "cookie";

import { OpenAPI } from "./client";
import { AxiosRequestConfig } from "axios";

/**
* Configures the base URL for the AI Assistant API which is path associated with
* the Django include.
*
* Configures the Axios request to include the CSRF token if it exists.
*
* @param baseURL Base URL of the AI Assistant API.
*
* @example
* configAIAssistant({ baseURL: "ai-assistant" });
*/
export function configAIAssistant({ baseURL }: { baseURL: string }) {
OpenAPI.BASE = baseURL;

OpenAPI.interceptors.request.use((request: AxiosRequestConfig) => {
const { csrftoken } = cookie.parse(document.cookie);
if (request.headers && csrftoken) {
request.headers["X-CSRFTOKEN"] = csrftoken;
}
return request;
});
}
15 changes: 9 additions & 6 deletions tests/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,9 @@ def authenticated_client(client):
# Assistant Views


def test_list_assistants_with_results(client):
response = client.get(reverse("django_ai_assistant:assistants_list"))
@pytest.mark.django_db()
def test_list_assistants_with_results(authenticated_client):
response = authenticated_client.get(reverse("django_ai_assistant:assistants_list"))

assert response.status_code == HTTPStatus.OK
assert response.json() == [{"id": "temperature_assistant", "name": "Temperature Assistant"}]
Expand All @@ -71,8 +72,9 @@ def test_does_not_list_assistants_if_unauthorized():
pass


def test_get_assistant_that_exists(client):
response = client.get(
@pytest.mark.django_db()
def test_get_assistant_that_exists(authenticated_client):
response = authenticated_client.get(
reverse(
"django_ai_assistant:assistant_detail", kwargs={"assistant_id": "temperature_assistant"}
)
Expand All @@ -82,9 +84,10 @@ def test_get_assistant_that_exists(client):
assert response.json() == {"id": "temperature_assistant", "name": "Temperature Assistant"}


def test_get_assistant_that_does_not_exist(client):
@pytest.mark.django_db()
def test_get_assistant_that_does_not_exist(authenticated_client):
with pytest.raises(AIAssistantNotDefinedError):
client.get(
authenticated_client.get(
reverse(
"django_ai_assistant:assistant_detail", kwargs={"assistant_id": "fake_assistant"}
)
Expand Down

0 comments on commit 9c2df83

Please sign in to comment.