diff --git a/ai_server/ai_server/settings.py b/ai_server/ai_server/settings.py index 8e0ebc8..33fba6e 100644 --- a/ai_server/ai_server/settings.py +++ b/ai_server/ai_server/settings.py @@ -40,6 +40,7 @@ "rest_framework", "corsheaders", "chat", + "toxicity", ] MIDDLEWARE = [ @@ -126,4 +127,7 @@ DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField" -CORS_ORIGIN_ALLOW_ALL = True \ No newline at end of file +CORS_ALLOWED_ORIGINS = [ + "http://localhost:4000", + "https://thalia.vercel.app", +] \ No newline at end of file diff --git a/ai_server/ai_server/urls.py b/ai_server/ai_server/urls.py index 5d9ad7d..a35d787 100644 --- a/ai_server/ai_server/urls.py +++ b/ai_server/ai_server/urls.py @@ -19,7 +19,8 @@ urlpatterns = [ # path("admin/", admin.site.urls), - path("", include("chat.urls")) + path("chat", include("chat.urls")), + path("toxic", include("toxicity.urls")), ] handler404 = "utils.exception_handler.error_404" diff --git a/ai_server/chat/llm_call.py b/ai_server/chat/llm_call.py index 5c52644..9bb5ee6 100644 --- a/ai_server/chat/llm_call.py +++ b/ai_server/chat/llm_call.py @@ -5,26 +5,41 @@ from langchain_core.output_parsers import StrOutputParser from .prompt import PROMPT -def call(input: str) -> Dict[str, Union[bool, str]]: - if "OPENAI_API_KEY" not in os.environ: +def call(user_input: str) -> Dict[str, Union[bool, str]]: + """ + Calls the OpenAI Chat API to generate a response. + + Args: + user_input (str): The input text to generate a response for. + + Returns: + Dict[str, Union[bool, str]]: A dictionary containing the success status and the generated response. + """ + if "OPENAI_API_KEY" not in os.environ or not os.environ["OPENAI_API_KEY"]: return { "success": False, - "message": "OpenAI API key not found", - } + "message": "OpenAI API key not found or empty", + } prompt = ChatPromptTemplate.from_template(PROMPT) model = ChatOpenAI(temperature=0) - chain = prompt | model | StrOutputParser() - - response:str = chain.invoke({"prompt": input}) + chain = prompt | model | StrOutputParser() + try: + response: str = chain.invoke({"prompt": user_input}) + except Exception as e: + return { + "success": False, + "message": f"Error in generation: {str(e)}", + } + if not response: return { "success": False, "message": "Error in generation", - } + } return { "success": True, "message": response, - } + } diff --git a/ai_server/chat/urls.py b/ai_server/chat/urls.py index e369ae5..a772ce9 100644 --- a/ai_server/chat/urls.py +++ b/ai_server/chat/urls.py @@ -2,6 +2,5 @@ from . import views urlpatterns = [ - path("", views.home, name="home"), - path('chat', views.index, name="routes"), + path("", views.index, name="chat"), ] \ No newline at end of file diff --git a/ai_server/chat/views.py b/ai_server/chat/views.py index 9585fe0..9cb51bf 100644 --- a/ai_server/chat/views.py +++ b/ai_server/chat/views.py @@ -4,13 +4,6 @@ from rest_framework import status from .llm_call import call as llm_call -@api_view(["GET", "POST"]) -def home(request): - return Response( - {"success":True ,"message":"connected successfully"}, - status=status.HTTP_200_OK - ) - @api_view(["POST"]) def index(request): content: dict = request.data diff --git a/ai_server/toxicity/__init__.py b/ai_server/toxicity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai_server/toxicity/admin.py b/ai_server/toxicity/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/ai_server/toxicity/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/ai_server/toxicity/apps.py b/ai_server/toxicity/apps.py new file mode 100644 index 0000000..5b2195d --- /dev/null +++ b/ai_server/toxicity/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class ToxicityConfig(AppConfig): + default_auto_field = "django.db.models.BigAutoField" + name = "toxicity" diff --git a/ai_server/toxicity/hf_call.py b/ai_server/toxicity/hf_call.py new file mode 100644 index 0000000..a14034d --- /dev/null +++ b/ai_server/toxicity/hf_call.py @@ -0,0 +1,57 @@ +from typing import Dict, Union, List +import requests +import os + +RESPONSE_TYPE = Dict[str, Union[str, float]] + + +def _transform_response(response: List[List[RESPONSE_TYPE]]) -> RESPONSE_TYPE: + """ + Transforms the response from the API call. + + Args: + response (List[List[RESPONSE_TYPE]]): The response from the API call. + + Returns: + RESPONSE_TYPE: The transformed response. + """ + if response[0][0]["score"] > response[0][1]["score"]: + return response[0][0] + return response[0][1] + + +def call(text: str) -> RESPONSE_TYPE: + """ + Calls the Hugging Face API to classify toxic comments. + + Args: + text (str): The text to classify. + + Returns: + RESPONSE_TYPE: The response from the API. + """ + if "HF_TOKEN" not in os.environ or not os.environ["HF_TOKEN"]: + return { + "success": False, + "message": "Huggingface Token not found or empty", + } + + HF_TOKEN = os.environ["HF_TOKEN"] + headers = {"Authorization": f"Bearer {HF_TOKEN}"} + api_url = ( + "https://api-inference.huggingface.co/models/martin-ha/toxic-comment-model" + ) + + response = requests.post(api_url, headers=headers, json={"inputs": text}) + + if response.status_code != 200: + return { + "success": False, + "message": f"API returned status code {response.status_code}", + } + + response_data = response.json() + transformed_response = _transform_response(response_data) + transformed_response["success"] = True + + return transformed_response diff --git a/ai_server/toxicity/migrations/__init__.py b/ai_server/toxicity/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ai_server/toxicity/models.py b/ai_server/toxicity/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/ai_server/toxicity/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/ai_server/toxicity/tests.py b/ai_server/toxicity/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/ai_server/toxicity/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/ai_server/toxicity/urls.py b/ai_server/toxicity/urls.py new file mode 100644 index 0000000..6d2f8a7 --- /dev/null +++ b/ai_server/toxicity/urls.py @@ -0,0 +1,6 @@ +from django.urls import path +from . import views + +urlpatterns = [ + path("", views.index, name="toxic"), +] \ No newline at end of file diff --git a/ai_server/toxicity/views.py b/ai_server/toxicity/views.py new file mode 100644 index 0000000..1e83572 --- /dev/null +++ b/ai_server/toxicity/views.py @@ -0,0 +1,39 @@ +from typing import Dict, Union +from rest_framework.decorators import api_view +from rest_framework.response import Response +from rest_framework import status +from .hf_call import call as hf_call + +@api_view(["POST"]) +def index(request): + content: dict = request.data + text = content.get("text") + if text is None: + return Response( + {"success": False, "message": "text is required !"}, + status=status.HTTP_400_BAD_REQUEST, + ) + if not isinstance(text, str): + return Response( + {"success": False, "message": "text should be str !"}, + status=status.HTTP_400_BAD_REQUEST, + ) + if not text: + return Response( + {"success": False, "message": "query should not be empty"}, + status=status.HTTP_400_BAD_REQUEST, + ) + + response:Dict[str, Union[bool, str]] = hf_call(text=text) + + if not response["success"]: + return Response( + response, + status=status.HTTP_500_INTERNAL_SERVER_ERROR, + ) + + return Response( + response, + status=status.HTTP_200_OK, + ) + diff --git a/client/src/Services/bodyServices.js b/client/src/Services/bodyServices.js new file mode 100644 index 0000000..950d103 --- /dev/null +++ b/client/src/Services/bodyServices.js @@ -0,0 +1,38 @@ +import thaliaAPI from "../API/thaliaAPI"; + +export const getTopics = async () => { + try { + const response = await thaliaAPI.get("/admin/my-body", { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const addTopic = async (formData) => { + try { + const response = await thaliaAPI.post("/admin/my-body", formData, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const deleteBody = async (bodyId) => { + try { + const response = await thaliaAPI.delete(`/admin/my-body/${bodyId}`, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const editBody = async (formData, bodyId) => { + try { + const response = await thaliaAPI.put(`/admin/my-body/${bodyId}`, formData); + return response.data; + } catch (error) { + console.log("error=>", error) + return error; + } +} \ No newline at end of file diff --git a/client/src/Services/rightServices.js b/client/src/Services/rightServices.js index ef248e2..4056d45 100644 --- a/client/src/Services/rightServices.js +++ b/client/src/Services/rightServices.js @@ -10,8 +10,6 @@ export const createRight = async (rightDetails) => { } export const editRight = async (rightDetails, rightId) => { try { - console.log("details", rightDetails) - console.log("right id", rightId) const response = await thaliaAPI.put(`/admin/rights/${rightId}`, rightDetails, { withCredentials: true }); return response.data; } catch (error) { diff --git a/client/src/Services/userService.js b/client/src/Services/userService.js new file mode 100644 index 0000000..a68d726 --- /dev/null +++ b/client/src/Services/userService.js @@ -0,0 +1,29 @@ +import thaliaAPI from "../API/thaliaAPI"; + +export const getUsers = async () => { + try { + const response = await thaliaAPI.get("/admin/users", { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const blockUser = async (userId) => { + try { + const response = await thaliaAPI.put(`/admin/users/block/${userId}`, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + +export const unBlockUser = async (userId) => { + try { + const response = await thaliaAPI.put(`/admin/users/unblock/${userId}`, { withCredentials: true }); + return response.data; + } catch (error) { + return error; + } +} + diff --git a/client/src/components/AddBody/AddBody.jsx b/client/src/components/AddBody/AddBody.jsx index 2a382e9..760184f 100644 --- a/client/src/components/AddBody/AddBody.jsx +++ b/client/src/components/AddBody/AddBody.jsx @@ -1,10 +1,13 @@ import { useState } from "react"; import { Modal } from "flowbite-react"; +import { addTopic } from "../../Services/bodyServices"; +import { toast } from "react-toastify"; +// eslint-disable-next-line react/prop-types function AddBody({ openModal, setOpenModal }) { const [formData, setFormData] = useState({ - body_name: "", - body_desc: "", + name: "", + content: "", }); const handleChange = (e) => { const { name, value } = e.target; @@ -13,6 +16,18 @@ function AddBody({ openModal, setOpenModal }) { [name]: value, }); }; + const handleAdd = () => { + const addNew = async () => { + const response = await addTopic(formData); + if (response.success === true) { + formData.name = ""; + formData.content = ""; + setOpenModal(false); + toast.success(response.message); + } + }; + addNew(); + }; return ( <> setOpenModal(false)}> @@ -25,10 +40,10 @@ function AddBody({ openModal, setOpenModal }) {

Name of the Topic

@@ -36,16 +51,19 @@ function AddBody({ openModal, setOpenModal }) { - diff --git a/client/src/components/AddRight/AddRight.jsx b/client/src/components/AddRight/AddRight.jsx index d1d826a..1ea6fdf 100644 --- a/client/src/components/AddRight/AddRight.jsx +++ b/client/src/components/AddRight/AddRight.jsx @@ -68,7 +68,7 @@ function AddRight({ setOpenModal, openModal }) { diff --git a/client/src/components/EditRight/EditRight.jsx b/client/src/components/EditRight/EditRight.jsx index 4e74fe2..e2ddc5a 100644 --- a/client/src/components/EditRight/EditRight.jsx +++ b/client/src/components/EditRight/EditRight.jsx @@ -66,7 +66,7 @@ function EditRight({ setOpenModal, openModal, rightDetails }) { - - -