2023-06-17 00:36:53 +03:00
|
|
|
from uuid import UUID
|
|
|
|
|
2023-07-04 18:56:54 +03:00
|
|
|
from auth import AuthBearer, get_current_user
|
2023-07-14 22:02:26 +03:00
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
2023-06-17 00:36:53 +03:00
|
|
|
from logger import get_logger
|
2023-09-13 14:47:12 +03:00
|
|
|
from models import UserIdentity, UserUsage
|
2023-09-21 10:35:53 +03:00
|
|
|
from models.brain_entity import PublicBrain
|
2023-09-13 14:47:12 +03:00
|
|
|
from models.databases.supabase.brains import (
|
|
|
|
BrainQuestionRequest,
|
|
|
|
BrainUpdatableProperties,
|
|
|
|
CreateBrainProperties,
|
|
|
|
)
|
|
|
|
from repository.brain import (
|
|
|
|
create_brain,
|
|
|
|
create_brain_user,
|
|
|
|
get_brain_details,
|
|
|
|
get_default_user_brain_or_create_new,
|
|
|
|
get_question_context_from_brain,
|
|
|
|
get_user_brains,
|
|
|
|
get_user_default_brain,
|
|
|
|
set_as_default_brain_for_user,
|
|
|
|
update_brain_by_id,
|
|
|
|
)
|
2023-09-21 10:35:53 +03:00
|
|
|
from repository.brain.get_public_brains import get_public_brains
|
2023-08-21 15:05:13 +03:00
|
|
|
from repository.prompt import delete_prompt_by_id, get_prompt_by_id
|
2023-09-20 17:24:56 +03:00
|
|
|
|
2023-08-21 15:05:13 +03:00
|
|
|
from routes.authorizations.brain_authorization import has_brain_authorization
|
2023-08-03 11:37:13 +03:00
|
|
|
from routes.authorizations.types import RoleEnum
|
2023-07-11 11:00:06 +03:00
|
|
|
|
2023-06-17 00:36:53 +03:00
|
|
|
logger = get_logger(__name__)
|
|
|
|
|
|
|
|
brain_router = APIRouter()
|
|
|
|
|
|
|
|
|
|
|
|
# get all brains
|
2023-06-30 10:08:40 +03:00
|
|
|
@brain_router.get("/brains/", dependencies=[Depends(AuthBearer())], tags=["Brain"])
|
2023-09-20 17:24:56 +03:00
|
|
|
async def brain_endpoint(
|
|
|
|
current_user: UserIdentity = Depends(get_current_user),
|
|
|
|
):
|
2023-06-17 00:36:53 +03:00
|
|
|
"""
|
|
|
|
Retrieve all brains for the current user.
|
|
|
|
|
|
|
|
- `current_user`: The current authenticated user.
|
|
|
|
- Returns a list of all brains registered for the user.
|
|
|
|
|
|
|
|
This endpoint retrieves all the brains associated with the current authenticated user. It returns a list of brains objects
|
|
|
|
containing the brain ID and brain name for each brain.
|
|
|
|
"""
|
2023-08-03 11:37:13 +03:00
|
|
|
brains = get_user_brains(current_user.id)
|
2023-06-17 00:36:53 +03:00
|
|
|
return {"brains": brains}
|
|
|
|
|
2023-06-21 11:16:44 +03:00
|
|
|
|
2023-09-21 10:35:53 +03:00
|
|
|
@brain_router.get(
|
|
|
|
"/brains/public", dependencies=[Depends(AuthBearer())], tags=["Brain"]
|
|
|
|
)
|
|
|
|
async def public_brains_endpoint() -> list[PublicBrain]:
|
|
|
|
"""
|
|
|
|
Retrieve all Quivr public brains
|
|
|
|
"""
|
|
|
|
return get_public_brains()
|
|
|
|
|
|
|
|
|
2023-07-14 22:02:26 +03:00
|
|
|
# get default brain
|
2023-07-02 03:19:30 +03:00
|
|
|
@brain_router.get(
|
|
|
|
"/brains/default/", dependencies=[Depends(AuthBearer())], tags=["Brain"]
|
|
|
|
)
|
2023-08-21 15:05:13 +03:00
|
|
|
async def get_default_brain_endpoint(
|
|
|
|
current_user: UserIdentity = Depends(get_current_user),
|
|
|
|
):
|
2023-06-28 20:39:27 +03:00
|
|
|
"""
|
2023-07-04 18:56:54 +03:00
|
|
|
Retrieve the default brain for the current user. If the user doesnt have one, it creates one.
|
2023-06-28 20:39:27 +03:00
|
|
|
|
|
|
|
- `current_user`: The current authenticated user.
|
|
|
|
- Returns the default brain for the user.
|
|
|
|
|
2023-07-02 03:19:30 +03:00
|
|
|
This endpoint retrieves the default brain associated with the current authenticated user.
|
2023-06-28 20:39:27 +03:00
|
|
|
The default brain is defined as the brain marked as default in the brains_users table.
|
|
|
|
"""
|
|
|
|
|
2023-07-14 22:02:26 +03:00
|
|
|
brain = get_default_user_brain_or_create_new(current_user)
|
2023-08-03 11:37:13 +03:00
|
|
|
return {"id": brain.brain_id, "name": brain.name, "rights": "Owner"}
|
2023-06-28 20:39:27 +03:00
|
|
|
|
2023-06-30 10:08:40 +03:00
|
|
|
|
2023-06-21 11:16:44 +03:00
|
|
|
@brain_router.get(
|
2023-07-11 11:00:06 +03:00
|
|
|
"/brains/{brain_id}/",
|
2023-07-13 18:54:23 +03:00
|
|
|
dependencies=[Depends(AuthBearer()), Depends(has_brain_authorization())],
|
2023-07-11 11:00:06 +03:00
|
|
|
tags=["Brain"],
|
2023-06-21 11:16:44 +03:00
|
|
|
)
|
2023-07-11 11:00:06 +03:00
|
|
|
async def get_brain_endpoint(
|
|
|
|
brain_id: UUID,
|
|
|
|
):
|
2023-06-17 00:36:53 +03:00
|
|
|
"""
|
|
|
|
Retrieve details of a specific brain by brain ID.
|
|
|
|
|
|
|
|
- `brain_id`: The ID of the brain to retrieve details for.
|
|
|
|
- Returns the brain ID and its history.
|
|
|
|
|
|
|
|
This endpoint retrieves the details of a specific brain identified by the provided brain ID. It returns the brain ID and its
|
|
|
|
history, which includes the brain messages exchanged in the brain.
|
|
|
|
"""
|
2023-08-01 17:25:02 +03:00
|
|
|
|
2023-08-03 11:37:13 +03:00
|
|
|
brain_details = get_brain_details(brain_id)
|
2023-08-01 17:25:02 +03:00
|
|
|
if brain_details is None:
|
|
|
|
raise HTTPException(
|
2023-07-14 22:02:26 +03:00
|
|
|
status_code=404,
|
2023-08-01 17:25:02 +03:00
|
|
|
detail="Brain details not found",
|
2023-07-14 22:02:26 +03:00
|
|
|
)
|
2023-06-21 11:16:44 +03:00
|
|
|
|
2023-08-01 17:25:02 +03:00
|
|
|
return brain_details
|
|
|
|
|
2023-06-17 00:36:53 +03:00
|
|
|
|
|
|
|
# create new brain
|
2023-06-30 10:08:40 +03:00
|
|
|
@brain_router.post("/brains/", dependencies=[Depends(AuthBearer())], tags=["Brain"])
|
|
|
|
async def create_brain_endpoint(
|
2023-08-03 11:37:13 +03:00
|
|
|
brain: CreateBrainProperties,
|
2023-08-21 15:05:13 +03:00
|
|
|
current_user: UserIdentity = Depends(get_current_user),
|
2023-06-21 11:16:44 +03:00
|
|
|
):
|
2023-06-17 00:36:53 +03:00
|
|
|
"""
|
2023-06-21 11:16:44 +03:00
|
|
|
Create a new brain with given
|
2023-06-20 17:17:13 +03:00
|
|
|
name
|
2023-06-17 00:36:53 +03:00
|
|
|
status
|
|
|
|
model
|
|
|
|
max_tokens
|
|
|
|
temperature
|
|
|
|
In the brains table & in the brains_users table and put the creator user as 'Owner'
|
|
|
|
"""
|
|
|
|
|
2023-08-03 11:37:13 +03:00
|
|
|
user_brains = get_user_brains(current_user.id)
|
2023-09-13 14:47:12 +03:00
|
|
|
userDailyUsage = UserUsage(
|
|
|
|
id=current_user.id,
|
|
|
|
email=current_user.email,
|
|
|
|
openai_api_key=current_user.openai_api_key,
|
|
|
|
)
|
|
|
|
userSettings = userDailyUsage.get_user_settings()
|
2023-07-20 19:17:55 +03:00
|
|
|
|
2023-09-13 14:47:12 +03:00
|
|
|
if len(user_brains) >= userSettings.get("max_brains", 5):
|
2023-07-20 19:17:55 +03:00
|
|
|
raise HTTPException(
|
|
|
|
status_code=429,
|
2023-09-13 14:47:12 +03:00
|
|
|
detail=f"Maximum number of brains reached ({userSettings.get('max_brains', 5)}).",
|
2023-07-20 19:17:55 +03:00
|
|
|
)
|
|
|
|
|
2023-08-03 11:37:13 +03:00
|
|
|
new_brain = create_brain(
|
|
|
|
brain,
|
|
|
|
)
|
|
|
|
default_brain = get_user_default_brain(current_user.id)
|
2023-06-28 20:39:27 +03:00
|
|
|
if default_brain:
|
2023-06-29 19:26:03 +03:00
|
|
|
logger.info(f"Default brain already exists for user {current_user.id}")
|
2023-08-03 11:37:13 +03:00
|
|
|
create_brain_user(
|
|
|
|
user_id=current_user.id,
|
|
|
|
brain_id=new_brain.brain_id,
|
|
|
|
rights=RoleEnum.Owner,
|
|
|
|
is_default_brain=False,
|
2023-07-02 03:19:30 +03:00
|
|
|
)
|
2023-06-28 20:39:27 +03:00
|
|
|
else:
|
2023-07-02 03:19:30 +03:00
|
|
|
logger.info(
|
|
|
|
f"Default brain does not exist for user {current_user.id}. It will be created."
|
|
|
|
)
|
2023-08-03 11:37:13 +03:00
|
|
|
create_brain_user(
|
|
|
|
user_id=current_user.id,
|
|
|
|
brain_id=new_brain.brain_id,
|
|
|
|
rights=RoleEnum.Owner,
|
|
|
|
is_default_brain=True,
|
2023-07-02 03:19:30 +03:00
|
|
|
)
|
2023-06-29 19:26:03 +03:00
|
|
|
|
2023-07-10 15:27:49 +03:00
|
|
|
return {
|
2023-08-03 11:37:13 +03:00
|
|
|
"id": new_brain.brain_id,
|
2023-07-10 15:27:49 +03:00
|
|
|
"name": brain.name,
|
2023-07-18 15:30:19 +03:00
|
|
|
"rights": "Owner",
|
2023-07-10 15:27:49 +03:00
|
|
|
}
|
2023-06-17 00:36:53 +03:00
|
|
|
|
2023-06-30 10:08:40 +03:00
|
|
|
|
2023-06-17 00:36:53 +03:00
|
|
|
# update existing brain
|
2023-06-21 11:16:44 +03:00
|
|
|
@brain_router.put(
|
2023-07-11 11:00:06 +03:00
|
|
|
"/brains/{brain_id}/",
|
|
|
|
dependencies=[
|
|
|
|
Depends(
|
|
|
|
AuthBearer(),
|
|
|
|
),
|
2023-07-25 16:22:17 +03:00
|
|
|
Depends(has_brain_authorization([RoleEnum.Editor, RoleEnum.Owner])),
|
2023-07-11 11:00:06 +03:00
|
|
|
],
|
|
|
|
tags=["Brain"],
|
2023-06-21 11:16:44 +03:00
|
|
|
)
|
2023-06-22 18:50:06 +03:00
|
|
|
async def update_brain_endpoint(
|
2023-06-21 11:16:44 +03:00
|
|
|
brain_id: UUID,
|
2023-08-03 11:37:13 +03:00
|
|
|
input_brain: BrainUpdatableProperties,
|
2023-06-21 11:16:44 +03:00
|
|
|
):
|
2023-06-17 00:36:53 +03:00
|
|
|
"""
|
2023-07-25 16:22:17 +03:00
|
|
|
Update an existing brain with new brain configuration
|
|
|
|
"""
|
|
|
|
|
2023-08-03 11:37:13 +03:00
|
|
|
# Remove prompt if it is private and no longer used by brain
|
|
|
|
if input_brain.prompt_id is None:
|
|
|
|
existing_brain = get_brain_details(brain_id)
|
|
|
|
if existing_brain is None:
|
|
|
|
raise HTTPException(
|
|
|
|
status_code=404,
|
|
|
|
detail="Brain not found",
|
|
|
|
)
|
|
|
|
prompt_id = existing_brain.prompt_id
|
|
|
|
if prompt_id is not None:
|
|
|
|
prompt = get_prompt_by_id(prompt_id)
|
|
|
|
if prompt is not None and prompt.status == "private":
|
|
|
|
delete_prompt_by_id(prompt_id)
|
|
|
|
|
|
|
|
update_brain_by_id(brain_id, input_brain)
|
|
|
|
|
2023-07-25 16:22:17 +03:00
|
|
|
return {"message": f"Brain {brain_id} has been updated."}
|
|
|
|
|
|
|
|
|
|
|
|
# set as default brain
|
|
|
|
@brain_router.post(
|
|
|
|
"/brains/{brain_id}/default",
|
|
|
|
dependencies=[
|
|
|
|
Depends(
|
|
|
|
AuthBearer(),
|
|
|
|
),
|
|
|
|
Depends(has_brain_authorization()),
|
|
|
|
],
|
|
|
|
tags=["Brain"],
|
|
|
|
)
|
|
|
|
async def set_as_default_brain_endpoint(
|
|
|
|
brain_id: UUID,
|
2023-08-21 15:05:13 +03:00
|
|
|
user: UserIdentity = Depends(get_current_user),
|
2023-07-25 16:22:17 +03:00
|
|
|
):
|
|
|
|
"""
|
|
|
|
Set a brain as default for the current user.
|
2023-06-17 00:36:53 +03:00
|
|
|
"""
|
2023-06-21 11:16:44 +03:00
|
|
|
|
2023-08-03 11:37:13 +03:00
|
|
|
set_as_default_brain_for_user(user.id, brain_id)
|
2023-06-17 00:36:53 +03:00
|
|
|
|
2023-07-25 16:22:17 +03:00
|
|
|
return {"message": f"Brain {brain_id} has been set as default brain."}
|
2023-08-27 10:38:41 +03:00
|
|
|
|
|
|
|
|
|
|
|
@brain_router.post(
|
|
|
|
"/brains/{brain_id}/question_context",
|
|
|
|
dependencies=[
|
|
|
|
Depends(
|
|
|
|
AuthBearer(),
|
|
|
|
),
|
|
|
|
Depends(has_brain_authorization()),
|
|
|
|
],
|
|
|
|
tags=["Brain"],
|
|
|
|
)
|
|
|
|
async def get_question_context_from_brain_endpoint(
|
|
|
|
brain_id: UUID,
|
|
|
|
request: BrainQuestionRequest,
|
|
|
|
):
|
|
|
|
"""
|
|
|
|
Get question context from brain
|
|
|
|
"""
|
|
|
|
|
|
|
|
context = get_question_context_from_brain(brain_id, request.question)
|
|
|
|
|
|
|
|
return {"context": context}
|