dtyago commited on
Commit
bfa9638
1 Parent(s): 5ab03c2

Login API implemented

Browse files
.env ADDED
@@ -0,0 +1 @@
 
 
1
+ EC_ADMIN_PWD='$2b$12$zybxm7XMoGCVV3ovNDcXt.r2QJUhtj7miYfEfuBw9UGqViTIRFg72'
Dockerfile CHANGED
@@ -12,28 +12,30 @@ RUN useradd -m -u 1000 user
12
  # Set environment variables for the non-root user
13
  ENV HOME=/home/user \
14
  PATH=/home/user/.local/bin:$PATH \
15
- NAME=EduConnect \
16
- EC_ADMIN_PWD='$2b$12$zybxm7XMoGCVV3ovNDcXt.r2QJUhtj7miYfEfuBw9UGqViTIRFg72'
17
 
18
  # Set the non-root user's home directory as the working directory
19
  WORKDIR $HOME
20
 
21
- # Copy the application files into the non-root user's home directory, ensuring the user owns the copied files
22
- COPY --chown=user:user . ./app
23
-
24
  # Create the /home/user/data directory and ensure it has the correct permissions
25
  RUN mkdir -p ./data && chown user:user ./data
26
 
27
  # Change to the non-root user
28
  USER user
29
 
30
- # Set the working directory to where the application files are
31
  WORKDIR $HOME/app
32
 
 
 
 
33
  # Install any needed packages specified in requirements.txt
34
  # As the non-root user, ensure packages are installed to the user's home directory
35
  RUN pip install --no-cache-dir --user -r requirements.txt
36
 
 
 
 
37
  # Make port 7860 available to the world outside this container
38
  EXPOSE 7860
39
 
@@ -42,4 +44,4 @@ EXPOSE 7860
42
  VOLUME /home/user/data
43
 
44
  # Run the FastAPI application using Uvicorn, binding to port 7860
45
- CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"]
 
12
  # Set environment variables for the non-root user
13
  ENV HOME=/home/user \
14
  PATH=/home/user/.local/bin:$PATH \
15
+ NAME=EduConnect
 
16
 
17
  # Set the non-root user's home directory as the working directory
18
  WORKDIR $HOME
19
 
 
 
 
20
  # Create the /home/user/data directory and ensure it has the correct permissions
21
  RUN mkdir -p ./data && chown user:user ./data
22
 
23
  # Change to the non-root user
24
  USER user
25
 
26
+ # Set the working directory to where the application files will be located
27
  WORKDIR $HOME/app
28
 
29
+ # Copy only the requirements.txt first to leverage Docker cache
30
+ COPY --chown=user:user requirements.txt ./
31
+
32
  # Install any needed packages specified in requirements.txt
33
  # As the non-root user, ensure packages are installed to the user's home directory
34
  RUN pip install --no-cache-dir --user -r requirements.txt
35
 
36
+ # Copy the rest of the application files into the container
37
+ COPY --chown=user:user . .
38
+
39
  # Make port 7860 available to the world outside this container
40
  EXPOSE 7860
41
 
 
44
  VOLUME /home/user/data
45
 
46
  # Run the FastAPI application using Uvicorn, binding to port 7860
47
+ CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860"]
README.md CHANGED
@@ -16,13 +16,12 @@ EduConnect/
16
  │ ├── __init__.py # Initializes the FastAPI app and global configurations
17
  │ ├── main.py # Entry point for the FastAPI application, defining routes
18
  │ ├── dependencies.py # Dependency utilities for JWT token verification, etc.
19
- │ ├── models.py # Database models for ORM
20
- │ ├── schemas.py # Pydantic schemas for request and response validation
21
  │ ├── api/
22
  │ │ ├── __init__.py
23
  │ │ ├── userlogin.py # Endpoint for user login functionality
24
  │ │ ├── userlogout.py # Endpoint for user logout functionality
25
  │ │ ├── userchat.py # Endpoint for chat functionality
 
26
  │ │ └── userhistory.py # Endpoint for loading chat history
27
  │ ├── admin/
28
  │ │ ├── __init__.py
@@ -32,11 +31,13 @@ EduConnect/
32
  │ │ └── user_registration.html # Template for user registration page
33
  │ └── utils/
34
  │ ├── __init__.py
 
 
35
  │ └── ec_image_utils.py # Integrates MTCNN and Facenet for login authentication
36
  ├── static/
37
- │ ├── css/
38
- │ ├── js/
39
- │ └── images/
40
  ├── Dockerfile # Docker configuration for setting up the environment
41
  ├── requirements.txt # Lists all Python library dependencies
42
  └── .env # Environment variables for configuration settings
 
16
  │ ├── __init__.py # Initializes the FastAPI app and global configurations
17
  │ ├── main.py # Entry point for the FastAPI application, defining routes
18
  │ ├── dependencies.py # Dependency utilities for JWT token verification, etc.
 
 
19
  │ ├── api/
20
  │ │ ├── __init__.py
21
  │ │ ├── userlogin.py # Endpoint for user login functionality
22
  │ │ ├── userlogout.py # Endpoint for user logout functionality
23
  │ │ ├── userchat.py # Endpoint for chat functionality
24
+ │ │ ├── userupload.py # Endpoint for file upload functionality
25
  │ │ └── userhistory.py # Endpoint for loading chat history
26
  │ ├── admin/
27
  │ │ ├── __init__.py
 
31
  │ │ └── user_registration.html # Template for user registration page
32
  │ └── utils/
33
  │ ├── __init__.py
34
+ │ ├── db.py # Centraized DB functions for ChromaDB collections, TinyDB
35
+ │ ├── jwt_utils.py # Utility for JWT tokens
36
  │ └── ec_image_utils.py # Integrates MTCNN and Facenet for login authentication
37
  ├── static/
38
+ │ ├── css/ # CSS for the administration portal
39
+ │ ├── js/ # Javascripts if any for administration portal
40
+ │ └── images/ # UI rendering images for administration page
41
  ├── Dockerfile # Docker configuration for setting up the environment
42
  ├── requirements.txt # Lists all Python library dependencies
43
  └── .env # Environment variables for configuration settings
app/api/login.py DELETED
@@ -1,23 +0,0 @@
1
- # # app/api/login.py
2
- # from fastapi import APIRouter, HTTPException, Depends, File, UploadFile
3
- # from ..utils.authentication import verify_user
4
- # from ..schemas import LoginSchema
5
- # from ..crud import get_user_by_email, create_access_token
6
-
7
- # router = APIRouter()
8
-
9
- # @router.post("/login/")
10
- # async def login(user_image: UploadFile = File(...)):
11
- # # Use MTCNN and Facenet to embed the image and verify user
12
- # user_verified, user_email = verify_user(user_image.file)
13
- # if not user_verified:
14
- # raise HTTPException(status_code=400, detail="Authentication Failed")
15
-
16
- # # Query ChromaDB for similarity and retrieve user details
17
- # user = get_user_by_email(user_email)
18
- # if not user:
19
- # raise HTTPException(status_code=404, detail="User not found")
20
-
21
- # # Generate JWT session token
22
- # access_token = create_access_token(data={"sub": user.email})
23
- # return {"access_token": access_token, "token_type": "bearer"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/api/userchat.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Depends, HTTPException, Body
2
+ from ..dependencies import get_current_user
3
+ from typing import Any
4
+
5
+ router = APIRouter()
6
+
7
+ @router.post("/user/chat")
8
+ async def chat_with_llama(user_input: str = Body(..., embed=True), current_user: Any = Depends(get_current_user)):
9
+ # Implement your logic to interact with LlamaV2 LLM here.
10
+ # Example response, replace with actual chat logic
11
+ chat_response = "Hello, how can I assist you today?"
12
+ return {"response": chat_response}
app/api/userlogin.py ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime, timedelta
2
+ from typing import Optional
3
+ from fastapi import APIRouter, File, UploadFile, HTTPException
4
+ from ..utils.db import tinydb_helper, chromadb_face_helper
5
+ from ..utils.jwt_utils import create_access_token
6
+ from ..utils.ec_image_utils import get_user_cropped_image_from_photo
7
+ import os
8
+ import uuid
9
+
10
+ router = APIRouter()
11
+ L2_FACE_THRESHOLD = 0.85 # distance value closer to 0 =>best match, >1 =>poor match
12
+
13
+ async def verify_user_face(file_path: str) -> Optional[dict]:
14
+ # Assuming `get_user_cropped_image_from_photo` returns the cropped face as expected by ChromaDB
15
+ face_img = get_user_cropped_image_from_photo(file_path)
16
+ if face_img is None:
17
+ return None
18
+
19
+ # Query the user's face in ChromaDB
20
+ query_results = chromadb_face_helper.query_user_face(face_img)
21
+ if query_results and len(query_results["ids"][0]) > 0:
22
+
23
+ chromadb_face_helper.print_query_results(query_results)
24
+
25
+ # Assuming the first result is the best match
26
+ l2_distance = query_results["distances"][0][0]
27
+ if l2_distance < L2_FACE_THRESHOLD: # l2 distance threshold for top matched face
28
+ user_id = query_results["ids"][0][0]
29
+ metadata = query_results["metadatas"][0][0]
30
+ return {"user_id": user_id, "metadata":metadata}
31
+ return None
32
+
33
+ @router.post("/user/login")
34
+ async def user_login(file: UploadFile = File(...)):
35
+ file_path = f"/tmp/{uuid.uuid4()}.jpg" # Generates a unique filename
36
+ with open(file_path, "wb") as buffer:
37
+ contents = await file.read()
38
+ buffer.write(contents)
39
+
40
+ # Perform face verification
41
+ verification_result = await verify_user_face(file_path)
42
+ if verification_result:
43
+ user_id = verification_result["user_id"]
44
+ metadata = verification_result["metadata"]
45
+ # Generate JWT token with user information
46
+ access_token = create_access_token(data={"sub": user_id, "name": metadata["name"], "role": metadata["role"]})
47
+
48
+ # Calculate expiration time for the token
49
+ expires_at = (datetime.utcnow() + timedelta(minutes=30)).isoformat() # Example expiration time
50
+
51
+ # Store the token in TinyDB
52
+ tinydb_helper.insert_token(user_id, access_token, expires_at)
53
+
54
+ return {"access_token": access_token, "token_type": "bearer"}
55
+ else:
56
+ raise HTTPException(status_code=400, detail="Face not recognized")
app/api/userlogout.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, Depends, HTTPException
2
+ from ..utils.db import tinydb_helper # Ensure this import is correct based on your project structure
3
+ from ..dependencies import oauth2_scheme
4
+
5
+ router = APIRouter()
6
+
7
+ @router.post("/user/logout")
8
+ async def user_logout(token: str = Depends(oauth2_scheme)):
9
+ try:
10
+ # Invalidate the token by removing it from the database
11
+ tinydb_helper.remove_token_by_value(token)
12
+ return {"message": "User logged out successfully"}
13
+ except Exception as e:
14
+ raise HTTPException(status_code=400, detail=f"Error during logout: {str(e)}")
app/api/userupload.py ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, UploadFile, File
2
+
3
+ router = APIRouter()
4
+
5
+ @router.post("/user/upload")
6
+ async def upload_file(file: UploadFile = File(...)):
7
+ file_location = f"/path/to/your/uploads/{file.filename}"
8
+ with open(file_location, "wb") as buffer:
9
+ contents = await file.read()
10
+ buffer.write(contents)
11
+ return {"filename": file.filename, "location": file_location}
app/dependencies.py ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import Depends, HTTPException, status
2
+ from fastapi.security import OAuth2PasswordBearer
3
+ from jose import jwt, JWTError
4
+ from .utils.db import tinydb_helper # Ensure correct import path
5
+ from .utils.jwt_utils import SECRET_KEY, ALGORITHM # Ensure these are defined in your jwt_utils.py
6
+
7
+ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
8
+
9
+ async def get_current_user(token: str = Depends(oauth2_scheme)):
10
+ credentials_exception = HTTPException(
11
+ status_code=status.HTTP_401_UNAUTHORIZED,
12
+ detail="Could not validate credentials",
13
+ headers={"WWW-Authenticate": "Bearer"},
14
+ )
15
+ try:
16
+ payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
17
+ user_id: str = payload.get("sub")
18
+ if user_id is None:
19
+ raise credentials_exception
20
+ token_data = tinydb_helper.query_token(user_id, token)
21
+ if not token_data:
22
+ raise credentials_exception
23
+ return token_data # Or return a user model based on the token_data
24
+ except JWTError:
25
+ raise credentials_exception
app/main.py CHANGED
@@ -7,20 +7,13 @@ from fastapi.responses import FileResponse, HTMLResponse, RedirectResponse
7
  from fastapi.templating import Jinja2Templates
8
 
9
  from .admin import admin_functions as admin
10
- from .utils.ec_image_utils import UserFaceEmbeddingFunction
 
 
11
 
12
- app = FastAPI()
13
-
14
- # Persitent storage for chromadb setup in /data volume
15
- ec_client = chromadb.PersistentClient("/home/user/data/chromadb")
16
- user_faces_db = ec_client.get_or_create_collection(name="user_faces_db", embedding_function=UserFaceEmbeddingFunction())
17
-
18
- @app.on_event("startup")
19
- async def startup_event():
20
- # Perform any necessary ChromaDB setup or checks here
21
- ec_client.heartbeat()
22
- print("ChromaDB setup completed.")
23
 
 
24
 
25
  # Add middleware
26
  # Set all origins to wildcard for simplicity, but you should limit this in production
@@ -32,6 +25,21 @@ app.add_middleware(
32
  allow_headers=["*"],
33
  )
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  # Mount static files
36
  app.mount("/static", StaticFiles(directory="static"), name="static")
37
 
@@ -68,4 +76,9 @@ async def handle_user_registration(request: Request, email: str = Form(...), nam
68
  return templates.TemplateResponse("registration_success.html", {"request": request})
69
  else:
70
  # Reload registration page with error message
71
- return templates.TemplateResponse("user_registration.html", {"request": request, "error": "Registration failed"})
 
 
 
 
 
 
7
  from fastapi.templating import Jinja2Templates
8
 
9
  from .admin import admin_functions as admin
10
+ from .utils.db import UserFaceEmbeddingFunction,ChromaDBFaceHelper
11
+ from .api import userlogin, userlogout, userchat, userupload
12
+ from .utils.db import tinydb_helper, ChromaDBFaceHelper
13
 
14
+ CHROMADB_LOC = "/home/user/data/chromadb"
 
 
 
 
 
 
 
 
 
 
15
 
16
+ app = FastAPI()
17
 
18
  # Add middleware
19
  # Set all origins to wildcard for simplicity, but you should limit this in production
 
25
  allow_headers=["*"],
26
  )
27
 
28
+ # Persitent storage for chromadb setup in /data volume
29
+ ec_client = chromadb.PersistentClient(CHROMADB_LOC)
30
+ # The following collection reference is needed for admin function to register face
31
+ user_faces_db = ec_client.get_or_create_collection(name="user_faces_db", embedding_function=UserFaceEmbeddingFunction())
32
+
33
+
34
+ @app.on_event("startup")
35
+ async def startup_event():
36
+ global chromadb_face_helper
37
+ # Assuming chromadb persistent store client for APIs is in helper
38
+ db_path = CHROMADB_LOC
39
+ chromadb_face_helper = ChromaDBFaceHelper(db_path) # Used by APIs
40
+ # Perform any other startup tasks here
41
+
42
+
43
  # Mount static files
44
  app.mount("/static", StaticFiles(directory="static"), name="static")
45
 
 
76
  return templates.TemplateResponse("registration_success.html", {"request": request})
77
  else:
78
  # Reload registration page with error message
79
+ return templates.TemplateResponse("user_registration.html", {"request": request, "error": "Registration failed"})
80
+
81
+ app.include_router(userlogin.router)
82
+ app.include_router(userlogout.router)
83
+ app.include_router(userchat.router)
84
+ app.include_router(userupload.router)
app/utils/chat_rag.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Model import
2
+ # Implement RAG using wvvocer
app/utils/db.py ADDED
@@ -0,0 +1,76 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ from tinydb import TinyDB, Query, where
3
+ from tinydb.storages import MemoryStorage
4
+ import chromadb
5
+ from chromadb.api.types import EmbeddingFunction, Embeddings, Image, Images
6
+ from keras_facenet import FaceNet
7
+ from typing import Any
8
+ from datetime import datetime, timedelta
9
+
10
+ CHROMADB_LOC = "/home/user/data/chromadb"
11
+
12
+ class TinyDBHelper:
13
+ def __init__(self):
14
+ self.db = TinyDB(storage=MemoryStorage)
15
+ self.tokens_table = self.db.table('tokens')
16
+
17
+ def insert_token(self, user_id: str, token: str, expires_at: str):
18
+ self.tokens_table.insert({'user_id': user_id, 'token': token, 'expires_at': expires_at})
19
+
20
+ def query_token(self, user_id: str, token: str) -> bool:
21
+ """Query to check if the token exists and is valid."""
22
+ User = Query()
23
+ # Assuming your tokens table contains 'user_id', 'token', and 'expires_at'
24
+ result = self.tokens_table.search((User.user_id == user_id) & (User.token == token))
25
+ # Optionally, check if the token is expired
26
+ expires_at = datetime.fromisoformat(result[0]['expires_at'])
27
+ if datetime.utcnow() > expires_at:
28
+ return False
29
+
30
+ return bool(result)
31
+
32
+ def remove_token_by_value(self, token: str):
33
+ """Remove a token based on its value."""
34
+ self.tokens_table.remove((where('token') == token))
35
+
36
+ ###### Class implementing Custom Embedding function for chroma db
37
+ #
38
+ class UserFaceEmbeddingFunction(EmbeddingFunction[Images]):
39
+ def __init__(self):
40
+ # Intitialize the FaceNet model
41
+ self.facenet = FaceNet()
42
+
43
+ def __call__(self, input: Images) -> Embeddings:
44
+ # Since the input images are assumed to be `numpy.ndarray` objects already,
45
+ # we can directly use them for embeddings extraction without additional processing.
46
+ # Ensure the input images are pre-cropped face images ready for embedding extraction.
47
+
48
+ # Extract embeddings using FaceNet for the pre-cropped face images.
49
+ embeddings_array = self.facenet.embeddings(input)
50
+
51
+ # Convert numpy array of embeddings to list of lists, as expected by Chroma.
52
+ return embeddings_array.tolist()
53
+
54
+
55
+ # Usage example:
56
+ # user_face_embedding_function = UserFaceEmbeddingFunction()
57
+ # Assuming `images` is a list of `numpy.ndarray` objects where each represents a pre-cropped face image ready for embedding extraction.
58
+ # embeddings = user_face_embedding_function(images)
59
+
60
+
61
+ class ChromaDBFaceHelper:
62
+ def __init__(self, db_path: str):
63
+ self.client = chromadb.PersistentClient(db_path)
64
+ self.user_faces_db = self.client.get_or_create_collection(name="user_faces_db", embedding_function=UserFaceEmbeddingFunction())
65
+
66
+ def query_user_face(self, presented_face: Any, n_results: int = 1):
67
+ return self.user_faces_db.query(query_images=[presented_face], n_results=n_results)
68
+
69
+ def print_query_results(self, query_results: dict) -> None:
70
+ for id, distance, metadata in zip(query_results["ids"][0], query_results['distances'][0], query_results['metadatas'][0]):
71
+ print(f'id: {id}, distance: {distance}, metadata: {metadata}')
72
+
73
+
74
+ # Initialize these helpers globally if they are to be used across multiple modules
75
+ tinydb_helper = TinyDBHelper()
76
+ chromadb_face_helper = ChromaDBFaceHelper(CHROMADB_LOC) # Initialization requires db_path
app/utils/ec_image_utils.py CHANGED
@@ -1,9 +1,6 @@
1
  import cv2
2
  from mtcnn.mtcnn import MTCNN
3
  import numpy as np
4
- from keras_facenet import FaceNet
5
- from chromadb.api.types import EmbeddingFunction, Embeddings, Image, Images
6
- from typing import List
7
 
8
 
9
  def load_image(filename):
@@ -79,27 +76,3 @@ def get_user_cropped_image_from_photo(filename):
79
  return cropped_face[0]
80
 
81
 
82
- ###### Class implementing Custom Embedding function for chroma db
83
- #
84
- class UserFaceEmbeddingFunction(EmbeddingFunction[Images]):
85
- def __init__(self):
86
- # Intitialize the FaceNet model
87
- self.facenet = FaceNet()
88
-
89
- def __call__(self, input: Images) -> Embeddings:
90
- # Since the input images are assumed to be `numpy.ndarray` objects already,
91
- # we can directly use them for embeddings extraction without additional processing.
92
- # Ensure the input images are pre-cropped face images ready for embedding extraction.
93
-
94
- # Extract embeddings using FaceNet for the pre-cropped face images.
95
- embeddings_array = self.facenet.embeddings(input)
96
-
97
- # Convert numpy array of embeddings to list of lists, as expected by Chroma.
98
- return embeddings_array.tolist()
99
-
100
-
101
- # Usage example:
102
- # user_face_embedding_function = UserFaceEmbeddingFunction()
103
- # Assuming `images` is a list of `numpy.ndarray` objects where each represents a pre-cropped face image ready for embedding extraction.
104
- # embeddings = user_face_embedding_function(images)
105
-
 
1
  import cv2
2
  from mtcnn.mtcnn import MTCNN
3
  import numpy as np
 
 
 
4
 
5
 
6
  def load_image(filename):
 
76
  return cropped_face[0]
77
 
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/utils/jwt_utils.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime, timedelta
2
+ from jose import JWTError, jwt
3
+ from typing import Any, Union
4
+ from tinydb import TinyDB, Query
5
+ from tinydb.storages import MemoryStorage
6
+
7
+
8
+ # Secret key to encode JWT tokens. In production, use a more secure key and keep it secret!
9
+ SECRET_KEY = "a_very_secret_key"
10
+ ALGORITHM = "HS256"
11
+ ACCESS_TOKEN_EXPIRE_MINUTES = 30 # The expiration time for the access token
12
+
13
+ db = TinyDB(storage=MemoryStorage)
14
+ tokens_table = db.table('tokens')
15
+
16
+ def insert_token(user_id: str, token: str, expires_in: timedelta):
17
+ expiration = datetime.utcnow() + expires_in
18
+ tokens_table.insert({'user_id': user_id, 'token': token, 'expires_at': expiration.isoformat()})
19
+
20
+ def validate_token(user_id: str, token: str) -> bool:
21
+ User = Query()
22
+ result = tokens_table.search((User.user_id == user_id) & (User.token == token))
23
+ if not result:
24
+ return False
25
+ # Check token expiration
26
+ expires_at = datetime.fromisoformat(result[0]['expires_at'])
27
+ if datetime.utcnow() > expires_at:
28
+ return False
29
+ return True
30
+
31
+ def create_access_token(data: dict, expires_delta: Union[timedelta, None] = None) -> str:
32
+ """
33
+ Creates a JWT access token.
34
+
35
+ :param data: A dictionary of claims (e.g., {"sub": user_id}) to include in the token.
36
+ :param expires_delta: A timedelta object representing how long the token is valid.
37
+ :return: A JWT token as a string.
38
+ """
39
+ to_encode = data.copy()
40
+ if expires_delta:
41
+ expire = datetime.utcnow() + expires_delta
42
+ else:
43
+ expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
44
+ to_encode.update({"exp": expire})
45
+ encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
46
+ return encoded_jwt
47
+
48
+ # Additional functions can be added here for verifying tokens, decoding tokens, etc.
docker-compose.yml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+ services:
3
+ educonnect:
4
+ image: python:3.9
5
+ command: ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "7860", "--reload"]
6
+ volumes:
7
+ - /Users/tyago/Workspace/EduConnect:/home/user/app
8
+ ports:
9
+ - "7860:7860"
10
+ environment:
11
+ - HOME=/home/user
12
+ - PATH=/home/user/.local/bin:$PATH
13
+ - NAME=EduConnect
14
+ - EC_ADMIN_PWD=$2b$12$zybxm7XMoGCVV3ovNDcXt.r2QJUhtj7miYfEfuBw9UGqViTIRFg72
15
+ user: "1000:1000"
16
+ working_dir: /home/user/app
17
+ env_file:
18
+ - .env
requirements.txt CHANGED
@@ -13,4 +13,5 @@ jinja2==3.0.* # For Admin site redndering
13
  bcrypt==4.1.* # For hashing secrets
14
  opencv-python-headless==4.5.5.* # For image handling images
15
  tensorflow # Tensorflow is needed by MTCNN for facial recognition
16
- scipy # The scipy is required for keras-facenet
 
 
13
  bcrypt==4.1.* # For hashing secrets
14
  opencv-python-headless==4.5.5.* # For image handling images
15
  tensorflow # Tensorflow is needed by MTCNN for facial recognition
16
+ scipy # The scipy is required for keras-facenet
17
+ tinydb # The in memory database for storing JWT tokens