quivr/backend/routes/knowledge_routes.py

103 lines
3.1 KiB
Python
Raw Normal View History

from uuid import UUID
from fastapi import APIRouter, Depends, Query
from logger import get_logger
from middlewares.auth import AuthBearer, get_current_user
from models import Brain
from modules.user.entity.user_identity import UserIdentity
from repository.files.delete_file import delete_file_from_storage
from repository.files.generate_file_signed_url import generate_file_signed_url
from repository.knowledge.get_all_knowledge import get_all_knowledge
from repository.knowledge.get_knowledge import get_knowledge
from repository.knowledge.remove_knowledge import remove_knowledge
from routes.authorizations.brain_authorization import (
RoleEnum,
has_brain_authorization,
validate_brain_authorization,
)
knowledge_router = APIRouter()
logger = get_logger(__name__)
@knowledge_router.get(
2023-09-25 13:13:48 +03:00
"/knowledge", dependencies=[Depends(AuthBearer())], tags=["Knowledge"]
)
async def list_knowledge_in_brain_endpoint(
brain_id: UUID = Query(..., description="The ID of the brain"),
current_user: UserIdentity = Depends(get_current_user),
):
"""
Retrieve and list all the knowledge in a brain.
"""
validate_brain_authorization(brain_id=brain_id, user_id=current_user.id)
knowledges = get_all_knowledge(brain_id)
Fixes string formatting when logging knowledge table (#1691) # Description ``` ====================================================================== backend-core | --- Logging error --- backend-core | Traceback (most recent call last): backend-core | File "/usr/local/lib/python3.11/logging/__init__.py", line 1110, in emit backend-core | msg = self.format(record) backend-core | ^^^^^^^^^^^^^^^^^^^ backend-core | File "/usr/local/lib/python3.11/logging/__init__.py", line 953, in format backend-core | return fmt.format(record) backend-core | ^^^^^^^^^^^^^^^^^^ backend-core | File "/usr/local/lib/python3.11/logging/__init__.py", line 687, in format backend-core | record.message = record.getMessage() backend-core | ^^^^^^^^^^^^^^^^^^^ backend-core | File "/usr/local/lib/python3.11/logging/__init__.py", line 377, in getMessage backend-core | msg = msg % self.args backend-core | ~~~~^~~~~~~~~~~ backend-core | TypeError: not all arguments converted during string formatting backend-core | Call stack: backend-core | File "<string>", line 1, in <module> backend-core | File "/usr/local/lib/python3.11/multiprocessing/spawn.py", line 122, in spawn_main backend-core | exitcode = _main(fd, parent_sentinel) backend-core | File "/usr/local/lib/python3.11/multiprocessing/spawn.py", line 135, in _main backend-core | return self._bootstrap(parent_sentinel) backend-core | File "/usr/local/lib/python3.11/multiprocessing/process.py", line 314, in _bootstrap backend-core | self.run() backend-core | File "/usr/local/lib/python3.11/multiprocessing/process.py", line 108, in run backend-core | self._target(*self._args, **self._kwargs) backend-core | File "/usr/local/lib/python3.11/site-packages/uvicorn/_subprocess.py", line 76, in subprocess_started backend-core | target(sockets=sockets) backend-core | File "/usr/local/lib/python3.11/site-packages/uvicorn/server.py", line 61, in run backend-core | return asyncio.run(self.serve(sockets=sockets)) backend-core | File "/usr/local/lib/python3.11/asyncio/runners.py", line 190, in run backend-core | return runner.run(main) backend-core | File "/usr/local/lib/python3.11/asyncio/runners.py", line 118, in run backend-core | return self._loop.run_until_complete(task) backend-core | File "/usr/local/lib/python3.11/asyncio/base_events.py", line 640, in run_until_complete backend-core | self.run_forever() backend-core | File "/usr/local/lib/python3.11/asyncio/base_events.py", line 607, in run_forever backend-core | self._run_once() backend-core | File "/usr/local/lib/python3.11/asyncio/base_events.py", line 1922, in _run_once backend-core | handle._run() backend-core | File "/usr/local/lib/python3.11/asyncio/events.py", line 80, in _run backend-core | self._context.run(self._callback, *self._args) backend-core | File "/usr/local/lib/python3.11/site-packages/uvicorn/protocols/http/h11_impl.py", line 428, in run_asgi backend-core | result = await app( # type: ignore[func-returns-value] backend-core | File "/usr/local/lib/python3.11/site-packages/uvicorn/middleware/proxy_headers.py", line 78, in __call__ backend-core | return await self.app(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/fastapi/applications.py", line 276, in __call__ backend-core | await super().__call__(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/applications.py", line 122, in __call__ backend-core | await self.middleware_stack(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/middleware/errors.py", line 162, in __call__ backend-core | await self.app(scope, receive, _send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 91, in __call__ backend-core | await self.simple_response(scope, receive, send, request_headers=headers) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/middleware/cors.py", line 146, in simple_response backend-core | await self.app(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/middleware/exceptions.py", line 68, in __call__ backend-core | await self.app(scope, receive, sender) backend-core | File "/usr/local/lib/python3.11/site-packages/fastapi/middleware/asyncexitstack.py", line 18, in __call__ backend-core | await self.app(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 718, in __call__ backend-core | await route.handle(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 276, in handle backend-core | await self.app(scope, receive, send) backend-core | File "/usr/local/lib/python3.11/site-packages/starlette/routing.py", line 66, in app backend-core | response = await func(request) backend-core | File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 237, in app backend-core | raw_response = await run_endpoint_function( backend-core | File "/usr/local/lib/python3.11/site-packages/fastapi/routing.py", line 163, in run_endpoint_function backend-core | return await dependant.call(**values) backend-core | File "/code/routes/knowledge_routes.py", line 37, in list_knowledge_in_brain_endpoint backend-core | logger.info("List of knowledge from knowledge table", knowledges) backend-core | Message: 'List of knowledge from knowledge table' backend-core | Arguments: ([Knowledge(id=UUID('b5ae6a25-1e8e-4fb5-a0c1-0039a8318ec3'), brain_id=UUID('7af64537-61cb-48e1-b3d1-c700d748b373'), file_name='Cradle to Cradle Criteria for the built environmen.pdf', url=None, extension='.pdf'), Knowledge(id=UUID('efb7ad5a-a13e-46f3-a580-4c574710ad15'), brain_id=UUID('7af64537-61cb-48e1-b3d1-c700d748b373'), file_name='GEG_2023_gebaeudeenergiegesetz_kompakt_und_praktisch.pdf', url=None, extension='.pdf'), Knowledge(id=UUID('9442f898-0fbe-46d2-b6ae-a726d62717bd'), brain_id=UUID('7af64537-61cb-48e1-b3d1-c700d748b373'), file_name='dgnb-kriterienkatalog-gebaeude-neubau-version-2023-auflage-2.pdf', url=None, extension='.pdf')],) ====================================================================== ``` ## Checklist before requesting a review Please delete options that are not relevant. - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented hard-to-understand areas - [x] I have ideally added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] Any dependent changes have been merged
2023-11-23 19:25:57 +03:00
logger.info(f"List of knowledge from knowledge table: {knowledges}")
return {"knowledges": knowledges}
@knowledge_router.delete(
2023-09-25 13:13:48 +03:00
"/knowledge/{knowledge_id}",
dependencies=[
Depends(AuthBearer()),
Depends(has_brain_authorization(RoleEnum.Owner)),
],
tags=["Knowledge"],
)
async def delete_endpoint(
knowledge_id: UUID,
current_user: UserIdentity = Depends(get_current_user),
brain_id: UUID = Query(..., description="The ID of the brain"),
):
"""
Delete a specific knowledge from a brain.
"""
validate_brain_authorization(brain_id=brain_id, user_id=current_user.id)
brain = Brain(id=brain_id)
knowledge = get_knowledge(knowledge_id)
file_name = knowledge.file_name if knowledge.file_name else knowledge.url
remove_knowledge(knowledge_id)
if knowledge.file_name:
delete_file_from_storage(f"{brain_id}/{knowledge.file_name}")
brain.delete_file_from_brain(knowledge.file_name)
elif knowledge.url:
brain.delete_file_from_brain(knowledge.url)
return {
"message": f"{file_name} of brain {brain_id} has been deleted by user {current_user.email}."
}
@knowledge_router.get(
"/knowledge/{knowledge_id}/signed_download_url",
dependencies=[Depends(AuthBearer())],
tags=["Knowledge"],
)
async def generate_signed_url_endpoint(
knowledge_id: UUID,
current_user: UserIdentity = Depends(get_current_user),
):
"""
Generate a signed url to download the file from storage.
"""
knowledge = get_knowledge(knowledge_id)
validate_brain_authorization(brain_id=knowledge.brain_id, user_id=current_user.id)
if knowledge.file_name == None:
raise Exception(f"Knowledge {knowledge_id} has no file_name associated with it")
file_path_in_storage = f"{knowledge.brain_id}/{knowledge.file_name}"
file_signed_url = generate_file_signed_url(file_path_in_storage)
return file_signed_url