mirror of
https://github.com/imartinez/privateGPT.git
synced 2025-07-13 15:14:09 +00:00
Updated with new api for chat with context filtering for based on files wrt to departments
This commit is contained in:
parent
1f5c0d5d7b
commit
500d4a1494
@ -1,5 +1,12 @@
|
|||||||
from fastapi import APIRouter, Depends, Request
|
from fastapi import APIRouter, Depends, Request, Security, HTTPException, status
|
||||||
|
from private_gpt.server.ingest.ingest_service import IngestService
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
from starlette.responses import StreamingResponse
|
from starlette.responses import StreamingResponse
|
||||||
|
|
||||||
from private_gpt.open_ai.extensions.context_filter import ContextFilter
|
from private_gpt.open_ai.extensions.context_filter import ContextFilter
|
||||||
@ -9,7 +16,8 @@ from private_gpt.open_ai.openai_models import (
|
|||||||
)
|
)
|
||||||
from private_gpt.server.chat.chat_router import ChatBody, chat_completion
|
from private_gpt.server.chat.chat_router import ChatBody, chat_completion
|
||||||
from private_gpt.server.utils.auth import authenticated
|
from private_gpt.server.utils.auth import authenticated
|
||||||
|
from private_gpt.users import crud, models, schemas
|
||||||
|
from private_gpt.users.api import deps
|
||||||
completions_router = APIRouter(prefix="/v1", dependencies=[Depends(authenticated)])
|
completions_router = APIRouter(prefix="/v1", dependencies=[Depends(authenticated)])
|
||||||
|
|
||||||
|
|
||||||
@ -83,3 +91,59 @@ def prompt_completion(
|
|||||||
context_filter=body.context_filter,
|
context_filter=body.context_filter,
|
||||||
)
|
)
|
||||||
return chat_completion(request, chat_body)
|
return chat_completion(request, chat_body)
|
||||||
|
|
||||||
|
|
||||||
|
@completions_router.post(
|
||||||
|
"/chat",
|
||||||
|
response_model=None,
|
||||||
|
summary="Completion",
|
||||||
|
responses={200: {"model": OpenAICompletion}},
|
||||||
|
tags=["Contextual Completions"],
|
||||||
|
)
|
||||||
|
def prompt_completion(
|
||||||
|
request: Request,
|
||||||
|
body: CompletionsBody,
|
||||||
|
db: Session = Depends(deps.get_db),
|
||||||
|
current_user: models.User = Security(
|
||||||
|
deps.get_current_user,
|
||||||
|
),
|
||||||
|
) -> OpenAICompletion | StreamingResponse:
|
||||||
|
try:
|
||||||
|
service = request.state.injector.get(IngestService)
|
||||||
|
|
||||||
|
department = crud.department.get_by_id(db, id=current_user.department_id)
|
||||||
|
if not department:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail=f"No department assigned to you")
|
||||||
|
documents = crud.documents.get_multi_documents(db, department_id=department.id)
|
||||||
|
if not documents:
|
||||||
|
raise HTTPException(status_code=status.HTTP_404_NOT_FOUND,
|
||||||
|
detail=f"No documents uploaded for your department.")
|
||||||
|
docs_list = [document.filename for document in documents]
|
||||||
|
docs_ids = []
|
||||||
|
for filename in docs_list:
|
||||||
|
doc_id = service.get_doc_ids_by_filename(filename)
|
||||||
|
docs_ids.extend(doc_id)
|
||||||
|
body.context_filter = {"docs_ids": docs_ids}
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
logger.error(f"There was an error: {str(e)}")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Internal Server Error",
|
||||||
|
)
|
||||||
|
|
||||||
|
messages = [OpenAIMessage(content=body.prompt, role="user")]
|
||||||
|
if body.system_prompt:
|
||||||
|
messages.insert(0, OpenAIMessage(
|
||||||
|
content=body.system_prompt, role="system"))
|
||||||
|
|
||||||
|
chat_body = ChatBody(
|
||||||
|
messages=messages,
|
||||||
|
use_context=body.use_context,
|
||||||
|
stream=body.stream,
|
||||||
|
include_sources=body.include_sources,
|
||||||
|
context_filter=body.context_filter,
|
||||||
|
)
|
||||||
|
return chat_completion(request, chat_body)
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
|
import traceback
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Literal, Optional, List
|
from typing import Literal, Optional, List
|
||||||
|
|
||||||
@ -8,7 +10,6 @@ from fastapi import APIRouter, Depends, HTTPException, Request, UploadFile, File
|
|||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
from pydantic import BaseModel, Field
|
from pydantic import BaseModel, Field
|
||||||
|
|
||||||
from private_gpt.home import Home
|
|
||||||
from private_gpt.users import crud, models, schemas
|
from private_gpt.users import crud, models, schemas
|
||||||
from private_gpt.users.api import deps
|
from private_gpt.users.api import deps
|
||||||
from private_gpt.users.constants.role import Role
|
from private_gpt.users.constants.role import Role
|
||||||
@ -194,7 +195,7 @@ def ingest_file(
|
|||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
docs_in = schemas.DocumentCreate(filename=file.filename, uploaded_by=current_user.id)
|
docs_in = schemas.DocumentCreate(filename=file.filename, uploaded_by=current_user.id, department_id=current_user.department_id)
|
||||||
crud.documents.create(db=db, obj_in=docs_in)
|
crud.documents.create(db=db, obj_in=docs_in)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
@ -216,7 +217,6 @@ def ingest_file(
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"There was an error uploading the file(s): {str(e)}")
|
logger.error(f"There was an error uploading the file(s): {str(e)}")
|
||||||
print("ERROR: ", e)
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
detail="Internal Server Error: Unable to ingest file.",
|
detail="Internal Server Error: Unable to ingest file.",
|
||||||
@ -250,13 +250,11 @@ async def common_ingest_logic(
|
|||||||
)
|
)
|
||||||
|
|
||||||
docs_in = schemas.DocumentCreate(
|
docs_in = schemas.DocumentCreate(
|
||||||
filename=file_name, uploaded_by=current_user.id)
|
filename=file_name, uploaded_by=current_user.id, department_id=current_user.department_id)
|
||||||
crud.documents.create(db=db, obj_in=docs_in)
|
crud.documents.create(db=db, obj_in=docs_in)
|
||||||
|
|
||||||
with open(upload_path, "wb") as f:
|
with open(upload_path, "wb") as f:
|
||||||
f.write(file.read())
|
f.write(file.read())
|
||||||
|
|
||||||
# Ingest binary data
|
|
||||||
file.seek(0) # Move the file pointer back to the beginning
|
file.seek(0) # Move the file pointer back to the beginning
|
||||||
ingested_documents = service.ingest_bin_data(file_name, file)
|
ingested_documents = service.ingest_bin_data(file_name, file)
|
||||||
|
|
||||||
@ -270,35 +268,7 @@ async def common_ingest_logic(
|
|||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"There was an error uploading the file(s): {str(e)}")
|
logger.error(f"There was an error uploading the file(s): {str(e)}")
|
||||||
print("ERROR: ", e)
|
|
||||||
raise HTTPException(
|
raise HTTPException(
|
||||||
status_code=500,
|
status_code=500,
|
||||||
detail="Internal Server Error: Unable to ingest file.",
|
detail="Internal Server Error: Unable to ingest file.",
|
||||||
)
|
)
|
||||||
|
|
||||||
from private_gpt.users.schemas import Document
|
|
||||||
|
|
||||||
@ingest_router.get("/ingest/list_files", response_model=List[schemas.Document], tags=["Ingestion"])
|
|
||||||
def list_files(
|
|
||||||
request: Request,
|
|
||||||
db: Session = Depends(deps.get_db),
|
|
||||||
skip: int = 0,
|
|
||||||
limit: int = 100,
|
|
||||||
current_user: models.User = Security(
|
|
||||||
deps.get_current_user,
|
|
||||||
scopes=[Role.ADMIN["name"], Role.SUPER_ADMIN["name"]],
|
|
||||||
|
|
||||||
)
|
|
||||||
):
|
|
||||||
try:
|
|
||||||
docs = crud.documents.get_multi(db, skip=skip, limit=limit)
|
|
||||||
return docs
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"There was an error uploading the file(s): {str(e)}")
|
|
||||||
print("ERROR: ", e)
|
|
||||||
raise HTTPException(
|
|
||||||
status_code=500,
|
|
||||||
detail="Internal Server Error: Unable to ingest file.",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
|||||||
from private_gpt.users.api.v1.routers import auth, roles, user_roles, users, subscriptions, companies, departments
|
from private_gpt.users.api.v1.routers import auth, roles, user_roles, users, subscriptions, companies, departments, documents
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
api_router = APIRouter(prefix="/v1")
|
api_router = APIRouter(prefix="/v1")
|
||||||
@ -10,4 +10,5 @@ api_router.include_router(user_roles.router)
|
|||||||
api_router.include_router(companies.router)
|
api_router.include_router(companies.router)
|
||||||
api_router.include_router(subscriptions.router)
|
api_router.include_router(subscriptions.router)
|
||||||
api_router.include_router(departments.router)
|
api_router.include_router(departments.router)
|
||||||
|
api_router.include_router(documents.router)
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ from private_gpt.users.constants.role import Role
|
|||||||
from private_gpt.users import crud, models, schemas
|
from private_gpt.users import crud, models, schemas
|
||||||
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/departments", tags=["Deparments"])
|
router = APIRouter(prefix="/departments", tags=["Departments"])
|
||||||
|
|
||||||
|
|
||||||
@router.get("", response_model=List[schemas.Department])
|
@router.get("", response_model=List[schemas.Department])
|
||||||
@ -42,7 +42,9 @@ def create_deparment(
|
|||||||
"""
|
"""
|
||||||
Create a new department
|
Create a new department
|
||||||
"""
|
"""
|
||||||
deparment = crud.department.create(db=db, obj_in=department_in)
|
company_id = current_user.company_id
|
||||||
|
department_create_in = schemas.DepartmentAdminCreate(name=department_in.name, company_id=company_id)
|
||||||
|
department = crud.department.create(db=db, obj_in=department_create_in)
|
||||||
department = jsonable_encoder(department)
|
department = jsonable_encoder(department)
|
||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
import traceback
|
||||||
|
import logging
|
||||||
|
from typing import Any, List
|
||||||
|
from sqlalchemy.orm import Session
|
||||||
|
from fastapi.responses import JSONResponse
|
||||||
|
from fastapi.encoders import jsonable_encoder
|
||||||
|
from fastapi import APIRouter, Depends, HTTPException, status, Security, Request
|
||||||
|
|
||||||
|
from private_gpt.users.api import deps
|
||||||
|
from private_gpt.users.constants.role import Role
|
||||||
|
from private_gpt.users import crud, models, schemas
|
||||||
|
from private_gpt.users.schemas import Document
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
router = APIRouter(prefix='/documents', tags=['Documents'])
|
||||||
|
|
||||||
|
@router.get("", response_model=List[schemas.Document])
|
||||||
|
def list_files(
|
||||||
|
request: Request,
|
||||||
|
db: Session = Depends(deps.get_db),
|
||||||
|
skip: int = 0,
|
||||||
|
limit: int = 100,
|
||||||
|
current_user: models.User = Security(
|
||||||
|
deps.get_current_user,
|
||||||
|
scopes=[Role.SUPER_ADMIN["name"]],
|
||||||
|
)
|
||||||
|
):
|
||||||
|
try:
|
||||||
|
docs = crud.documents.get_multi(db, skip=skip, limit=limit)
|
||||||
|
return docs
|
||||||
|
except Exception as e:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
logger.error(f"There was an error listing the file(s).")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Internal Server Error: Unable to ingest file.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('{department_id}', response_model=List[schemas.Document])
|
||||||
|
def list_files_by_department(
|
||||||
|
request: Request,
|
||||||
|
department_id: int,
|
||||||
|
db: Session = Depends(deps.get_db),
|
||||||
|
skip: int = 0,
|
||||||
|
limit: int = 100,
|
||||||
|
current_user: models.User = Security(
|
||||||
|
deps.get_current_user,
|
||||||
|
scopes=[Role.SUPER_ADMIN["name"]],
|
||||||
|
)
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Listing the documents by the department id
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
docs = crud.documents.get_multi_documents(
|
||||||
|
db, department_id=department_id, skip=skip, limit=limit)
|
||||||
|
return docs
|
||||||
|
except Exception as e:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
logger.error(f"There was an error listing the file(s).")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Internal Server Error: Unable to ingest file.",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@router.get('/files', response_model=List[schemas.DocumentList])
|
||||||
|
def list_files_by_department(
|
||||||
|
request: Request,
|
||||||
|
db: Session = Depends(deps.get_db),
|
||||||
|
skip: int = 0,
|
||||||
|
limit: int = 100,
|
||||||
|
current_user: models.User = Security(
|
||||||
|
deps.get_current_user,
|
||||||
|
scopes=[Role.ADMIN["name"]],
|
||||||
|
)
|
||||||
|
):
|
||||||
|
'''
|
||||||
|
Listing the documents by the ADMIN of the Department
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
department_id = current_user.department_id
|
||||||
|
docs = crud.documents.get_multi_documents(
|
||||||
|
db, department_id=department_id, skip=skip, limit=limit)
|
||||||
|
return docs
|
||||||
|
except Exception as e:
|
||||||
|
print(traceback.format_exc())
|
||||||
|
logger.error(f"There was an error listing the file(s).")
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=500,
|
||||||
|
detail="Internal Server Error: Unable to ingest file.",
|
||||||
|
)
|
@ -95,7 +95,8 @@ def update_username(
|
|||||||
user_data = schemas.UserBaseSchema(
|
user_data = schemas.UserBaseSchema(
|
||||||
email=user.email,
|
email=user.email,
|
||||||
fullname=user.fullname,
|
fullname=user.fullname,
|
||||||
company_id=user.company_id
|
company_id=user.company_id,
|
||||||
|
department_id=user.department_id,
|
||||||
)
|
)
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=status.HTTP_200_OK,
|
status_code=status.HTTP_200_OK,
|
||||||
@ -114,11 +115,11 @@ def read_user_me(
|
|||||||
Get current user.
|
Get current user.
|
||||||
"""
|
"""
|
||||||
role = current_user.user_role.role.name if current_user.user_role else None
|
role = current_user.user_role.role.name if current_user.user_role else None
|
||||||
print("THe role is: ", role)
|
|
||||||
user_data = schemas.Profile(
|
user_data = schemas.Profile(
|
||||||
email=current_user.email,
|
email=current_user.email,
|
||||||
fullname=current_user.fullname,
|
fullname=current_user.fullname,
|
||||||
company_id = current_user.company_id,
|
company_id = current_user.company_id,
|
||||||
|
department_id=current_user.department_id,
|
||||||
role =role
|
role =role
|
||||||
)
|
)
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
@ -151,6 +152,7 @@ def change_password(
|
|||||||
email=current_user.email,
|
email=current_user.email,
|
||||||
fullname=current_user.fullname,
|
fullname=current_user.fullname,
|
||||||
company_id= current_user.company_id,
|
company_id= current_user.company_id,
|
||||||
|
department_id=current_user.department_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
@ -205,6 +207,8 @@ def update_user(
|
|||||||
id=user.id,
|
id=user.id,
|
||||||
email=user.email,
|
email=user.email,
|
||||||
fullname=user.fullname,
|
fullname=user.fullname,
|
||||||
|
company_id=user.company_id,
|
||||||
|
department_id=user.department_id,
|
||||||
)
|
)
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=status.HTTP_200_OK,
|
status_code=status.HTTP_200_OK,
|
||||||
@ -254,6 +258,7 @@ def admin_change_password(
|
|||||||
email=user.email,
|
email=user.email,
|
||||||
fullname=user.fullname,
|
fullname=user.fullname,
|
||||||
company_id=user.company_id,
|
company_id=user.company_id,
|
||||||
|
department_id=user.department_id,
|
||||||
)
|
)
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
status_code=status.HTTP_200_OK,
|
status_code=status.HTTP_200_OK,
|
||||||
@ -331,8 +336,7 @@ def admin_update_user(
|
|||||||
role = crud.user_role.update(db, db_obj=user_role, obj_in=role_in)
|
role = crud.user_role.update(db, db_obj=user_role, obj_in=role_in)
|
||||||
|
|
||||||
user_in = schemas.UserUpdate(fullname=user_update.fullname,
|
user_in = schemas.UserUpdate(fullname=user_update.fullname,
|
||||||
email=existing_user.email, company_id=existing_user.user_role.company_id)
|
email=existing_user.email, company_id=existing_user.user_role.company_id, department_id=user_update.department_id)
|
||||||
print("User in: ", user_in)
|
|
||||||
user = crud.user.update(db, db_obj=existing_user, obj_in=user_in)
|
user = crud.user.update(db, db_obj=existing_user, obj_in=user_in)
|
||||||
|
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from private_gpt.users.schemas.deparment import DepartmentCreate, DepartmentUpdate
|
from private_gpt.users.schemas.department import DepartmentCreate, DepartmentUpdate
|
||||||
from private_gpt.users.models.department import Department
|
from private_gpt.users.models.department import Department
|
||||||
from private_gpt.users.crud.base import CRUDBase
|
from private_gpt.users.crud.base import CRUDBase
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
@ -2,7 +2,7 @@ from sqlalchemy.orm import Session
|
|||||||
from private_gpt.users.schemas.documents import DocumentCreate, DocumentUpdate
|
from private_gpt.users.schemas.documents import DocumentCreate, DocumentUpdate
|
||||||
from private_gpt.users.models.document import Document
|
from private_gpt.users.models.document import Document
|
||||||
from private_gpt.users.crud.base import CRUDBase
|
from private_gpt.users.crud.base import CRUDBase
|
||||||
from typing import Optional
|
from typing import Optional, List
|
||||||
|
|
||||||
|
|
||||||
class CRUDDocuments(CRUDBase[Document, DocumentCreate, DocumentUpdate]):
|
class CRUDDocuments(CRUDBase[Document, DocumentCreate, DocumentUpdate]):
|
||||||
@ -12,5 +12,15 @@ class CRUDDocuments(CRUDBase[Document, DocumentCreate, DocumentUpdate]):
|
|||||||
def get_by_filename(self, db: Session, *, file_name: str) -> Optional[Document]:
|
def get_by_filename(self, db: Session, *, file_name: str) -> Optional[Document]:
|
||||||
return db.query(self.model).filter(Document.filename == file_name).first()
|
return db.query(self.model).filter(Document.filename == file_name).first()
|
||||||
|
|
||||||
|
def get_multi_documents(
|
||||||
|
self, db: Session, *,department_id: int, skip: int = 0, limit: int = 100
|
||||||
|
) -> List[Document]:
|
||||||
|
return (
|
||||||
|
db.query(self.model)
|
||||||
|
.filter(Document.department_id == department_id)
|
||||||
|
.offset(skip)
|
||||||
|
.limit(limit)
|
||||||
|
.all()
|
||||||
|
)
|
||||||
|
|
||||||
documents = CRUDDocuments(Document)
|
documents = CRUDDocuments(Document)
|
||||||
|
@ -4,5 +4,5 @@ from .user import User, UserCreate, UserInDB, UserUpdate, UserBaseSchema, Profil
|
|||||||
from .user_role import UserRole, UserRoleCreate, UserRoleInDB, UserRoleUpdate
|
from .user_role import UserRole, UserRoleCreate, UserRoleInDB, UserRoleUpdate
|
||||||
from .subscription import Subscription, SubscriptionBase, SubscriptionCreate, SubscriptionUpdate
|
from .subscription import Subscription, SubscriptionBase, SubscriptionCreate, SubscriptionUpdate
|
||||||
from .company import Company, CompanyBase, CompanyCreate, CompanyUpdate
|
from .company import Company, CompanyBase, CompanyCreate, CompanyUpdate
|
||||||
from .documents import Document, DocumentCreate, DocumentsBase, DocumentUpdate
|
from .documents import Document, DocumentCreate, DocumentsBase, DocumentUpdate, DocumentList
|
||||||
from .deparment import Department, DepartmentCreate, DepartmentUpdate
|
from .department import Department, DepartmentCreate, DepartmentUpdate, DepartmentAdminCreate
|
@ -21,6 +21,11 @@ class DepartmentInDB(DepartmentBase):
|
|||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
|
||||||
|
class DepartmentAdminCreate(DepartmentBase):
|
||||||
|
company_id: int
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
orm_mode = True
|
||||||
|
|
||||||
class Department(DepartmentInDB):
|
class Department(DepartmentInDB):
|
||||||
pass
|
pass
|
@ -9,16 +9,23 @@ class DocumentsBase(BaseModel):
|
|||||||
|
|
||||||
class DocumentCreate(DocumentsBase):
|
class DocumentCreate(DocumentsBase):
|
||||||
uploaded_by: int
|
uploaded_by: int
|
||||||
|
department_id: int
|
||||||
|
|
||||||
|
|
||||||
class DocumentUpdate(DocumentsBase):
|
class DocumentUpdate(DocumentsBase):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
class DocumentList(DocumentsBase):
|
||||||
|
id: int
|
||||||
|
uploaded_by: int
|
||||||
|
uploaded_at: datetime
|
||||||
|
|
||||||
|
|
||||||
class Document(DocumentsBase):
|
class Document(DocumentsBase):
|
||||||
id: int
|
id: int
|
||||||
uploaded_by: int
|
uploaded_by: int
|
||||||
uploaded_at: datetime
|
uploaded_at: datetime
|
||||||
|
department_id: int
|
||||||
|
|
||||||
class Config:
|
class Config:
|
||||||
orm_mode = True
|
orm_mode = True
|
||||||
|
Loading…
Reference in New Issue
Block a user