Skip to content

Commit

Permalink
Merge pull request #4 from tmeftah/nikhil_raikar
Browse files Browse the repository at this point in the history
Started addressing and cleaning the backend to make it ready for futher extensions
  • Loading branch information
tmeftah authored Aug 4, 2024
2 parents dd9f81d + b35713a commit dbfab5e
Show file tree
Hide file tree
Showing 21 changed files with 447 additions and 242 deletions.
40 changes: 40 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
name: FastAPI CI

on: [push, pull_request]

jobs:
test:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
cache: 'pip'

- name: Install dependencies
run: |
cd backend
pip install -r requirements.txt
- name: Start FastAPI app
run: |
cd backend
nohup fastapi dev > /dev/null 2>&1 &
echo $! > uvicorn.pid
sleep 10
- name: Check FastAPI /health endpoint
run: |
response=$(curl -s http://127.0.0.1:8000/health)
echo "Response: $response"
if [ "$response" == '{"status":"Active"}' ]; then
echo "Health check passed"
else
echo "Health check failed"
exit 1
fi
Empty file added backend/api/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions backend/api/health.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

from fastapi import APIRouter

health_router = APIRouter()


@health_router.get("/health")
async def check_health():
return {"status": "Active"}
31 changes: 31 additions & 0 deletions backend/api/query.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from fastapi import APIRouter
from fastapi.responses import StreamingResponse

from backend.rag_llms_langchain import chain
from backend.embeddings.ingest import get_vectorstore

import json
import uuid


query_router = APIRouter()


@query_router.get("/query")
async def query(query: str):
# if current_user.role < 5:
# raise HTTPException(status_code=403, detail="Only admin users can delete other users")
store = get_vectorstore()
docs = store.invoke(query)

print(20*"*", "docs", 20*"*", "\n", docs)

async def stream_generator():
# Use the LangChain model to generate text
print(20*'*', "\n", query)
async for text in chain.astream({"input": query, "context": docs}):
yield json.dumps({"event_id": str(uuid.uuid4()), "data": text})

# TODO here we have to add the metadata/source

return StreamingResponse(stream_generator(), media_type="application/x-ndjson")
26 changes: 26 additions & 0 deletions backend/api/token.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

from fastapi import APIRouter, Depends, HTTPException
from backend.pydantic_models import Token
from backend.oauth import authenticate_user, create_access_token
from backend.config import ACCESS_TOKEN_EXPIRE_MINUTES
from fastapi.security import OAuth2PasswordRequestForm
from datetime import timedelta


token_router = APIRouter()


@token_router.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
user = authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=401,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={"sub": user.username}, expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
73 changes: 73 additions & 0 deletions backend/api/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@

from fastapi import APIRouter, Depends, HTTPException
from backend.sqlalchemy_models import User
from backend.sessions import session
from backend.oauth import encrypt_password, get_current_user


user_router = APIRouter()



@user_router.get("/users/me")
async def read_users_me(current_user: User = Depends(get_current_user)):
return {"username": current_user.username, "role": current_user.role}


@user_router.get("/users/")
async def read_users(current_user: User = Depends(get_current_user)):
if current_user.role < 5:
raise HTTPException(
status_code=403, detail="Only admin users can view all users")
return [{"username": user.username, "role": user.role} for user in session.query(User).all()]


@user_router.get("/users/{user_id}")
async def read_user(user_id: int, current_user: User = Depends(get_current_user)):
if current_user.id != user_id and current_user.role < 5:
raise HTTPException(
status_code=403, detail="Only admin users can view other users")
user = session.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
return {"username": user.username, "role": user.role}


@user_router.post("/users/")
async def create_user(username: str, password: str, role: int, current_user: User = Depends(get_current_user)):
if current_user.role < 5:
raise HTTPException(
status_code=403, detail="Only admin users can create new users")
user = User(username=username,
password_hash=encrypt_password(password), role=role)
session.add(user)
session.commit()
return {"username": user.username, "role": user.role}


@user_router.put("/users/{user_id}")
async def update_user(user_id: int, username: str, password: str, role: int, current_user: User = Depends(get_current_user)):
if current_user.id != user_id and current_user.role < 5:
raise HTTPException(
status_code=403, detail="Only admin users can update other users")
user = session.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
user.username = username
user.password = password
user.role = role
session.commit()
return {"username": user.username, "role": user.role}


@user_router.delete("/users/{user_id}")
async def delete_user(user_id: int, current_user: User = Depends(get_current_user)):
if current_user.id != user_id and current_user.role < 5:
raise HTTPException(
status_code=403, detail="Only admin users can delete other users")
user = session.query(User).filter(User.id == user_id).first()
if not user:
raise HTTPException(status_code=404, detail="User not found")
session.delete(user)
session.commit()
return {"message": "User deleted"}
13 changes: 13 additions & 0 deletions backend/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# No origins are limited for now
# All origins are allowed for now and this
# must be changed
origins = [
"http://localhost",
"http://127.0.0.1:8000",
]


Empty file added backend/embeddings/__init__.py
Empty file.
File renamed without changes.
Loading

0 comments on commit dbfab5e

Please sign in to comment.