Spaces:
Runtime error
Runtime error
Commit
Β·
2ecc792
1
Parent(s):
5267759
Separated the backend and frontend
Browse files- .devcontainer/devcontainer.json +0 -33
- TechdocsAPI/.gitattributes +35 -0
- TechdocsAPI/Dockerfile +11 -0
- TechdocsAPI/README.md +48 -0
- TechdocsAPI/app.py +1 -0
- TechdocsAPI/backend/__init__.py +49 -0
- TechdocsAPI/backend/core/ConfigEnv.py +32 -0
- TechdocsAPI/backend/core/ExceptionHandlers.py +27 -0
- TechdocsAPI/backend/core/Exceptions.py +45 -0
- TechdocsAPI/backend/core/__init__.py +0 -0
- TechdocsAPI/backend/models/__init__.py +3 -0
- TechdocsAPI/backend/models/auth.py +32 -0
- TechdocsAPI/backend/models/generic.py +14 -0
- TechdocsAPI/backend/models/inference.py +6 -0
- TechdocsAPI/backend/router.py +65 -0
- TechdocsAPI/backend/services/__init__.py +0 -0
- TechdocsAPI/backend/services/auth/__init__.py +2 -0
- TechdocsAPI/backend/services/auth/ops.py +109 -0
- TechdocsAPI/backend/services/auth/utils/JWTBearer.py +75 -0
- TechdocsAPI/backend/services/auth/utils/auth_funcs.py +171 -0
- TechdocsAPI/backend/services/db/__init__.py +0 -0
- TechdocsAPI/backend/services/db/utils/DBQueries.py +66 -0
- TechdocsAPI/backend/utils/DBConnection.py +57 -0
- TechdocsAPI/backend/utils/__init__.py +1 -0
- TechdocsAPI/backend/utils/prompt.txt +11 -0
- TechdocsAPI/backend/utils/scopes.py +3 -0
- TechdocsAPI/requirements.txt +10 -0
- Login.py β frontend/Login.py +1 -1
- {pages β frontend/pages}/Code.py +2 -2
- requirements.txt β frontend/requirements.txt +0 -0
- π‘_Home.py β frontend/π‘_Home.py +1 -1
.devcontainer/devcontainer.json
DELETED
@@ -1,33 +0,0 @@
|
|
1 |
-
{
|
2 |
-
"name": "Python 3",
|
3 |
-
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
|
4 |
-
"image": "mcr.microsoft.com/devcontainers/python:1-3.11-bullseye",
|
5 |
-
"customizations": {
|
6 |
-
"codespaces": {
|
7 |
-
"openFiles": [
|
8 |
-
"README.md",
|
9 |
-
"frontend/π‘_Home.py"
|
10 |
-
]
|
11 |
-
},
|
12 |
-
"vscode": {
|
13 |
-
"settings": {},
|
14 |
-
"extensions": [
|
15 |
-
"ms-python.python",
|
16 |
-
"ms-python.vscode-pylance"
|
17 |
-
]
|
18 |
-
}
|
19 |
-
},
|
20 |
-
"updateContentCommand": "[ -f packages.txt ] && sudo apt update && sudo apt upgrade -y && sudo xargs apt install -y <packages.txt; [ -f requirements.txt ] && pip3 install --user -r requirements.txt; pip3 install --user streamlit; echo 'β
Packages installed and Requirements met'",
|
21 |
-
"postAttachCommand": {
|
22 |
-
"server": "streamlit run frontend/π‘_Home.py --server.enableCORS false --server.enableXsrfProtection false"
|
23 |
-
},
|
24 |
-
"portsAttributes": {
|
25 |
-
"8501": {
|
26 |
-
"label": "Application",
|
27 |
-
"onAutoForward": "openPreview"
|
28 |
-
}
|
29 |
-
},
|
30 |
-
"forwardPorts": [
|
31 |
-
8501
|
32 |
-
]
|
33 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
TechdocsAPI/.gitattributes
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
TechdocsAPI/Dockerfile
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11
|
2 |
+
|
3 |
+
WORKDIR /backend
|
4 |
+
|
5 |
+
COPY ./requirements.txt /backend/requirements.txt
|
6 |
+
|
7 |
+
RUN pip install --no-cache-dir --upgrade -r /backend/requirements.txt
|
8 |
+
|
9 |
+
COPY . .
|
10 |
+
|
11 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
TechdocsAPI/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: TechdocsAPI
|
3 |
+
emoji: π’
|
4 |
+
colorFrom: green
|
5 |
+
colorTo: green
|
6 |
+
sdk: docker
|
7 |
+
pinned: false
|
8 |
+
---
|
9 |
+
|
10 |
+
# Techdocs: A code documentation generator
|
11 |
+
|
12 |
+
## Introduction
|
13 |
+
|
14 |
+
**Code Documentation Generation** is a tool that generates documentation for your code. It is a simple tool that can be used by anyone who wants to generate documentation for their code. It leverages the power of **OpenAI GPT-3, Huggingface Transformers, Langchain and Clarifai** to generate documentation for your code.
|
15 |
+
|
16 |
+
To use the application, you need to provide your code as input. The tool will analyze your code and generate documentation for it. The documentation will include comments, descriptions, parameters, return values, examples, and more.
|
17 |
+
|
18 |
+
It is a useful tool for developers who want to document their code without spending too much time and effort. It can help you improve the readability, maintainability, and quality of your code. It can also help you share your code with others more easily.
|
19 |
+
|
20 |
+
## Installation
|
21 |
+
> Download zip or Clone the repository and run the following command in the terminal to install the required packages.
|
22 |
+
|
23 |
+
> We recommend using a virtual environment for the installation.
|
24 |
+
|
25 |
+
```bash
|
26 |
+
$ git clone https://github.com/HemanthSai7/Techdocs
|
27 |
+
$ cd Techdocs
|
28 |
+
$ pip install -r requirements.txt
|
29 |
+
$ -- Run backend
|
30 |
+
$ uvicorn app:app --reload
|
31 |
+
```
|
32 |
+
|
33 |
+
## Tech Stack Used
|
34 |
+
![Python](https://img.shields.io/badge/python-3670A0?style=for-the-badge&logo=python&logoColor=ffdd54)
|
35 |
+
![Azure](https://img.shields.io/badge/azure_SQL-%230072C6.svg?style=for-the-badge&logo=microsoftazure&logoColor=white)
|
36 |
+
![FastAPI](https://img.shields.io/badge/FastAPI-005571?style=for-the-badge&logo=fastapi)
|
37 |
+
![Vercel](https://img.shields.io/badge/vercel-%23000000.svg?style=for-the-badge&logo=vercel&logoColor=white)
|
38 |
+
![JWT](https://img.shields.io/badge/JWT-black?style=for-the-badge&logo=JSON%20web%20tokens)
|
39 |
+
![GitHub Actions](https://img.shields.io/badge/github%20actions-%232671E5.svg?style=for-the-badge&logo=githubactions&logoColor=white)
|
40 |
+
![Streamlit](https://img.shields.io/badge/Streamlit-EA6566?style=for-the-badge&logo=streamlit&logoColor=white)
|
41 |
+
![Langchain](https://img.shields.io/badge/Langchain-F70A8D?style=for-the-badge&logo=langchain&logoColor=white)
|
42 |
+
![Clarifai](https://img.shields.io/badge/Clarifai-FFA500?style=for-the-badge&logo=clarifai&logoColor=white)
|
43 |
+
|
44 |
+
## Team Members
|
45 |
+
| Name | Github |
|
46 |
+
| --- | --- |
|
47 |
+
| Mayuresh Agashe | [Mayuresh Agashe](https://github.com/mayureshagashe2105) |
|
48 |
+
| Hemanth Sai Garladinne | [Hemanth Sai Garladinne](https://github.com/HemanthSai7) |
|
TechdocsAPI/app.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
from backend import app
|
TechdocsAPI/backend/__init__.py
ADDED
@@ -0,0 +1,49 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import mysql.connector
|
2 |
+
from mysql.connector import errorcode
|
3 |
+
|
4 |
+
from fastapi import FastAPI, status
|
5 |
+
from fastapi.exceptions import HTTPException
|
6 |
+
|
7 |
+
from backend.utils import DBConnection
|
8 |
+
from backend.core.ConfigEnv import config
|
9 |
+
|
10 |
+
from langchain.llms import Clarifai
|
11 |
+
from langchain.chains import LLMChain
|
12 |
+
from langchain.prompts import PromptTemplate
|
13 |
+
|
14 |
+
app = FastAPI(title="Techdocs",
|
15 |
+
version="V0.0.1",
|
16 |
+
description="API for automatic code documentation generation!"
|
17 |
+
)
|
18 |
+
|
19 |
+
from backend import router
|
20 |
+
|
21 |
+
try:
|
22 |
+
dbconnection = DBConnection()
|
23 |
+
test_conn = DBConnection.get_client().get_server_info()
|
24 |
+
|
25 |
+
# send prompt wizardcoderLM-70b-instruct-GGUF model
|
26 |
+
with open("backend/utils/prompt.txt",'r') as f:
|
27 |
+
prompt = f.read()
|
28 |
+
|
29 |
+
prompt = PromptTemplate(template=prompt, input_variables=['instruction'])
|
30 |
+
|
31 |
+
llm = Clarifai(
|
32 |
+
pat = config.CLARIFAI_PAT,
|
33 |
+
user_id = config.USER_ID,
|
34 |
+
app_id = config.APP_ID,
|
35 |
+
model_id = config.MODEL_ID,
|
36 |
+
model_version_id=config.MODEL_VERSION_ID,
|
37 |
+
)
|
38 |
+
|
39 |
+
llmchain = LLMChain(
|
40 |
+
prompt=prompt,
|
41 |
+
llm=llm
|
42 |
+
)
|
43 |
+
app.state.llmchain = llmchain
|
44 |
+
|
45 |
+
|
46 |
+
except mysql.connector.Error as err:
|
47 |
+
raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail=str(err))
|
48 |
+
|
49 |
+
|
TechdocsAPI/backend/core/ConfigEnv.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Config class for handling env variables.
|
2 |
+
"""
|
3 |
+
from functools import lru_cache
|
4 |
+
|
5 |
+
from pydantic import BaseSettings
|
6 |
+
|
7 |
+
|
8 |
+
class Settings(BaseSettings):
|
9 |
+
HOSTNAME: str
|
10 |
+
DATABASE: str
|
11 |
+
UID: str
|
12 |
+
PASSWORD: str
|
13 |
+
ALGORITHM:str
|
14 |
+
JWT_SECRET_KEY:str
|
15 |
+
JWT_REFRESH_SECRET_KEY:str
|
16 |
+
# OPENAI_KEY:str
|
17 |
+
APP_ID:str
|
18 |
+
USER_ID:str
|
19 |
+
MODEL_ID:str
|
20 |
+
CLARIFAI_PAT:str
|
21 |
+
MODEL_VERSION_ID:str
|
22 |
+
|
23 |
+
class Config:
|
24 |
+
env_file = ".env"
|
25 |
+
|
26 |
+
|
27 |
+
@lru_cache()
|
28 |
+
def get_settings():
|
29 |
+
return Settings()
|
30 |
+
|
31 |
+
|
32 |
+
config = get_settings()
|
TechdocsAPI/backend/core/ExceptionHandlers.py
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from backend import app
|
2 |
+
from .Exceptions import *
|
3 |
+
|
4 |
+
from fastapi.responses import JSONResponse
|
5 |
+
from fastapi.requests import Request
|
6 |
+
from fastapi import status
|
7 |
+
|
8 |
+
|
9 |
+
|
10 |
+
@app.exception_handler(ExistingUserException)
|
11 |
+
async def handle_existing_user_found(request: Request, exec: ExistingUserException):
|
12 |
+
return JSONResponse(status_code=status.HTTP_226_IM_USED,
|
13 |
+
content=repr(exec)
|
14 |
+
)
|
15 |
+
|
16 |
+
|
17 |
+
@app.exception_handler(InvalidCredentialsException)
|
18 |
+
async def handle_login_failed(request: Request, exec: InvalidCredentialsException):
|
19 |
+
return JSONResponse(status_code=status.HTTP_403_FORBIDDEN,
|
20 |
+
content=repr(exec)
|
21 |
+
)
|
22 |
+
|
23 |
+
@app.exception_handler(InfoNotFoundException)
|
24 |
+
async def handle_info_not_found(request: Request, exec: InfoNotFoundException):
|
25 |
+
return JSONResponse(status_code=status.HTTP_401_UNAUTHORIZED,
|
26 |
+
content=repr(exec)
|
27 |
+
)
|
TechdocsAPI/backend/core/Exceptions.py
ADDED
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
|
3 |
+
from backend.models import GeneralResponse, TokenSchema
|
4 |
+
|
5 |
+
|
6 |
+
class InvalidCredentialsException(Exception):
|
7 |
+
def __init__(self, token_result: GeneralResponse):
|
8 |
+
self.token_result = token_result
|
9 |
+
self.set_statuses()
|
10 |
+
super(InvalidCredentialsException, self).__init__()
|
11 |
+
|
12 |
+
def set_statuses(self):
|
13 |
+
self.token_result.status = 'login_failed'
|
14 |
+
|
15 |
+
def __repr__(self):
|
16 |
+
return json.dumps(self.token_result)
|
17 |
+
|
18 |
+
class ExistingUserException(Exception):
|
19 |
+
def __init__(self, response_result: GeneralResponse):
|
20 |
+
self.response_result = response_result
|
21 |
+
self.set_statuses()
|
22 |
+
super(ExistingUserException, self).__init__()
|
23 |
+
|
24 |
+
def set_statuses(self):
|
25 |
+
self.response_result.status = f'failed'
|
26 |
+
self.response_result.message.append(f'user with this AADHAR Number already has an account')
|
27 |
+
self.response_result.message[0] = 'authenticated'
|
28 |
+
|
29 |
+
def __repr__(self):
|
30 |
+
return json.dumps(self.response_result)
|
31 |
+
|
32 |
+
class InfoNotFoundException(Exception):
|
33 |
+
def __init__(self, response_result: GeneralResponse, message: str):
|
34 |
+
self.response_result = response_result
|
35 |
+
self.message = message
|
36 |
+
self.set_statuses()
|
37 |
+
super(InfoNotFoundException, self).__init__(message)
|
38 |
+
|
39 |
+
def set_statuses(self):
|
40 |
+
self.response_result['status'] = 'abort'
|
41 |
+
self.response_result['message'][0] = 'authenticated'
|
42 |
+
self.response_result['message'].append(self.message)
|
43 |
+
|
44 |
+
def __repr__(self):
|
45 |
+
return json.dumps(self.response_result)
|
TechdocsAPI/backend/core/__init__.py
ADDED
File without changes
|
TechdocsAPI/backend/models/__init__.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from .auth import *
|
2 |
+
from .generic import *
|
3 |
+
from .inference import *
|
TechdocsAPI/backend/models/auth.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field, EmailStr
|
2 |
+
from typing import Union, List, Tuple
|
3 |
+
|
4 |
+
from .generic import Base
|
5 |
+
|
6 |
+
|
7 |
+
class TokenSchema(Base):
|
8 |
+
access_token: str
|
9 |
+
refresh_token: str
|
10 |
+
|
11 |
+
|
12 |
+
class UserAuth(Base):
|
13 |
+
username: str = Field(..., description="username")
|
14 |
+
password: str = Field(..., min_length=5, max_length=24, description="user password")
|
15 |
+
email: EmailStr
|
16 |
+
|
17 |
+
|
18 |
+
class User(Base):
|
19 |
+
username: str
|
20 |
+
email: EmailStr
|
21 |
+
|
22 |
+
class TokenPayload(Base):
|
23 |
+
sub: str = None
|
24 |
+
exp: int = None
|
25 |
+
|
26 |
+
|
27 |
+
class LoginCreds(Base):
|
28 |
+
username: str
|
29 |
+
password: str
|
30 |
+
|
31 |
+
class APIKey(Base):
|
32 |
+
api_key: str
|
TechdocsAPI/backend/models/generic.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import List
|
3 |
+
|
4 |
+
|
5 |
+
class Base(BaseModel):
|
6 |
+
@classmethod
|
7 |
+
def get_instance(cls, **kwargs):
|
8 |
+
return cls(**kwargs)
|
9 |
+
|
10 |
+
|
11 |
+
class GeneralResponse(Base):
|
12 |
+
status:str
|
13 |
+
message: List[str]
|
14 |
+
data:dict
|
TechdocsAPI/backend/models/inference.py
ADDED
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel
|
2 |
+
from typing import List
|
3 |
+
from .generic import Base
|
4 |
+
|
5 |
+
class Inference(Base):
|
6 |
+
docstr:str
|
TechdocsAPI/backend/router.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import Request, Depends, UploadFile
|
2 |
+
from fastapi.middleware.cors import CORSMiddleware
|
3 |
+
|
4 |
+
from backend import app
|
5 |
+
from backend.utils import DBConnection
|
6 |
+
from backend.models import *
|
7 |
+
from backend.services.auth import *
|
8 |
+
|
9 |
+
|
10 |
+
app.add_middleware(
|
11 |
+
CORSMiddleware,
|
12 |
+
allow_origins=["*"],
|
13 |
+
allow_credentials=True,
|
14 |
+
allow_methods=["*"],
|
15 |
+
allow_headers=["*"],
|
16 |
+
)
|
17 |
+
|
18 |
+
@app.get("/api/response_check", tags=["Resource Server"])
|
19 |
+
def api_response_check():
|
20 |
+
response_result = GeneralResponse.get_instance(data={},
|
21 |
+
status="not_allowed",
|
22 |
+
message=["Not authenticated"]
|
23 |
+
)
|
24 |
+
|
25 |
+
try:
|
26 |
+
db_msg = ""
|
27 |
+
if DBConnection.is_connected():
|
28 |
+
db_msg = "Connection Successful to db!"
|
29 |
+
else:
|
30 |
+
db_msg = "Connection failed to db"
|
31 |
+
|
32 |
+
response_result.message.append(db_msg)
|
33 |
+
|
34 |
+
except Exception as e:
|
35 |
+
print("Exception :", e)
|
36 |
+
|
37 |
+
return response_result
|
38 |
+
|
39 |
+
@app.post("/auth/signup", summary="Creates new user account", response_model=GeneralResponse, tags=["Auth Server"])
|
40 |
+
async def signup(response: UserAuth):
|
41 |
+
response_result = GeneralResponse.get_instance(data={},
|
42 |
+
status="not_allowed",
|
43 |
+
message=["Not authenticated"]
|
44 |
+
)
|
45 |
+
ops_signup(response_result, response)
|
46 |
+
|
47 |
+
return response_result
|
48 |
+
|
49 |
+
@app.post("/auth/login", summary="Logs in user", response_model=TokenSchema, tags=["Auth Server"])
|
50 |
+
async def login(response:LoginCreds):
|
51 |
+
return ops_login(response)
|
52 |
+
|
53 |
+
@app.put("/auth/regenerate_api_key",summary="Forget Password",response_model=APIKey,tags=["Auth Server"],dependencies=[Depends(JWTBearer())])
|
54 |
+
async def regenerate_api_key(access_token: str = Depends(JWTBearer())):
|
55 |
+
user_sub=Auth.get_user_credentials(access_token)
|
56 |
+
|
57 |
+
return ops_regenerate_api_key(user_sub)
|
58 |
+
|
59 |
+
@app.post("/api/inference", summary="Inference", response_model=Inference, tags=["Resource Server"], dependencies=[Depends(JWTBearer())])
|
60 |
+
async def inference(code_block:str, api_key: str,access_token:str=Depends(JWTBearer())):
|
61 |
+
user_sub=Auth.get_user_credentials(access_token)
|
62 |
+
|
63 |
+
print("after res")
|
64 |
+
|
65 |
+
return ops_inference(code_block,api_key,user_sub)
|
TechdocsAPI/backend/services/__init__.py
ADDED
File without changes
|
TechdocsAPI/backend/services/auth/__init__.py
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
from .ops import *
|
2 |
+
from .utils.JWTBearer import *
|
TechdocsAPI/backend/services/auth/ops.py
ADDED
@@ -0,0 +1,109 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from .utils.auth_funcs import *
|
2 |
+
from .utils.JWTBearer import *
|
3 |
+
from backend.models import *
|
4 |
+
from backend.services.db.utils.DBQueries import DBQueries
|
5 |
+
from backend.core.Exceptions import *
|
6 |
+
from backend import app
|
7 |
+
|
8 |
+
# import openai
|
9 |
+
# from transformers import RobertaTokenizer, T5ForConditionalGeneration
|
10 |
+
|
11 |
+
def ops_signup(response_result: GeneralResponse, data: UserAuth):
|
12 |
+
"""Wrapper method to handle signup process.
|
13 |
+
|
14 |
+
Args:
|
15 |
+
response_result: FrontendResponseModel. A TypedDict to return the
|
16 |
+
response captured from the API to the frontend.
|
17 |
+
data: UserAuth. New user's prospective credentials from the frontend
|
18 |
+
to create their account.
|
19 |
+
|
20 |
+
Raises:
|
21 |
+
ExistingUserException: If account with entered AADHAR Number already exists.
|
22 |
+
"""
|
23 |
+
# querying database to check if user already exist
|
24 |
+
user = DBQueries.fetch_data_from_database('auth', ['username', 'email'], f"username='{data.username}' OR email='{data.email}'")
|
25 |
+
if len(list(user)) != 0:
|
26 |
+
# user with the entered credentials already exists
|
27 |
+
raise ExistingUserException(response_result)
|
28 |
+
|
29 |
+
DBQueries.insert_to_database('auth', (data.username, Auth.get_password_hash(data.password), data.email),
|
30 |
+
['username', 'password', 'email'])
|
31 |
+
|
32 |
+
response_result.status = 'success'
|
33 |
+
response_result.message = [f'User created successfully']
|
34 |
+
|
35 |
+
def ops_login(data:LoginCreds):
|
36 |
+
"""Wrapper method to handle login process.
|
37 |
+
|
38 |
+
Args:
|
39 |
+
data: LoginCreds. User's credentials from the frontend to login to their account.
|
40 |
+
|
41 |
+
Returns:
|
42 |
+
TokenSchema. A Pydantic BaseModel to return the JWT tokens to the frontend.
|
43 |
+
|
44 |
+
Raises:
|
45 |
+
InvalidCredentialsException: If account with entered credentials does not exist.
|
46 |
+
"""
|
47 |
+
# querying database to check if user already exist
|
48 |
+
response_result = GeneralResponse.get_instance(data={},
|
49 |
+
status="not_allowed",
|
50 |
+
message=["Not authenticated"]
|
51 |
+
)
|
52 |
+
user = DBQueries.fetch_data_from_database('auth', ['username', 'password'], f"username='{data.username}'")
|
53 |
+
user = list(user)
|
54 |
+
if len(user) == 0:
|
55 |
+
# user with the entered credentials does not exist
|
56 |
+
raise InvalidCredentialsException(response_result)
|
57 |
+
user = user[0]
|
58 |
+
if not Auth.verify_password(data.password, user[1]) and Auth.verify_username(data.username, user[0]):
|
59 |
+
# password is incorrect
|
60 |
+
raise InvalidCredentialsException(response_result)
|
61 |
+
|
62 |
+
# password is correct
|
63 |
+
return TokenSchema(access_token=Auth.create_access_token(data.username),
|
64 |
+
refresh_token=Auth.create_refresh_token(data.username),
|
65 |
+
)
|
66 |
+
|
67 |
+
def ops_regenerate_api_key(username:str) -> APIKey:
|
68 |
+
|
69 |
+
user_API_entry = DBQueries.fetch_data_from_database('api_key', 'apikey', f"username='{username}'")
|
70 |
+
user_API_entry = list(user_API_entry)
|
71 |
+
apikey = None
|
72 |
+
|
73 |
+
if len(user_API_entry) != 0:
|
74 |
+
apikey = APIKey(api_key=Auth.generate_api_key(username))
|
75 |
+
DBQueries.update_data_in_database('api_key','apikey',f"username='{username}'", apikey.api_key)
|
76 |
+
|
77 |
+
else:
|
78 |
+
apikey = Auth.generate_api_key(username)
|
79 |
+
DBQueries.insert_to_database('api_key', (username, apikey), ['username', 'apikey'])
|
80 |
+
apikey = APIKey(api_key=apikey)
|
81 |
+
|
82 |
+
return apikey
|
83 |
+
|
84 |
+
|
85 |
+
|
86 |
+
def ops_inference(source_code:str,api_key:str,username:str):
|
87 |
+
response_result = GeneralResponse.get_instance(data={},
|
88 |
+
status="not_allowed",
|
89 |
+
message=["Not authenticated"]
|
90 |
+
)
|
91 |
+
|
92 |
+
user=DBQueries.fetch_data_from_database('api_key', ['apikey'], f"username='{username}'")
|
93 |
+
if len(list(user)) == 0:
|
94 |
+
# user with the entered credentials does not exist
|
95 |
+
raise InfoNotFoundException(response_result,"User not found")
|
96 |
+
elif list(user)[0][0]!=api_key:
|
97 |
+
raise InvalidCredentialsException(response_result)
|
98 |
+
|
99 |
+
def generate_docstring(source_code_message: str):
|
100 |
+
|
101 |
+
|
102 |
+
llm_response = app.state.llmchain.run({"instruction": source_code_message})
|
103 |
+
|
104 |
+
docstring = Inference(docstr=llm_response)
|
105 |
+
|
106 |
+
|
107 |
+
return docstring
|
108 |
+
|
109 |
+
return generate_docstring(source_code)
|
TechdocsAPI/backend/services/auth/utils/JWTBearer.py
ADDED
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Custom Authentication & Authorization bearer to authenticate and authorize
|
2 |
+
users based on the following factors:
|
3 |
+
1. username
|
4 |
+
2.password
|
5 |
+
3.email
|
6 |
+
|
7 |
+
This utility class validates generated JWTs and grants scoped access to users
|
8 |
+
according to their roles.
|
9 |
+
"""
|
10 |
+
from backend.core.ConfigEnv import config
|
11 |
+
from backend.models import TokenPayload
|
12 |
+
|
13 |
+
from datetime import datetime
|
14 |
+
|
15 |
+
from fastapi import Request, HTTPException
|
16 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
17 |
+
from pydantic import ValidationError
|
18 |
+
from jose import jwt
|
19 |
+
|
20 |
+
|
21 |
+
class JWTBearer(HTTPBearer):
|
22 |
+
"""Custom bearer to validate access tokens.
|
23 |
+
|
24 |
+
Args:
|
25 |
+
auto_error: bool = True. Internal param to allow auto error detection.
|
26 |
+
|
27 |
+
Raises:
|
28 |
+
HHTTPException(403): If authentication scheme is not `Bearer`.
|
29 |
+
HTTPException(403): If the access token is invalid or expired.
|
30 |
+
HTTPException(403): If authorization code is invalid.
|
31 |
+
"""
|
32 |
+
def __init__(self, auto_error: bool = True):
|
33 |
+
super(JWTBearer, self).__init__(auto_error=auto_error)
|
34 |
+
|
35 |
+
async def __call__(self, request: Request) -> str:
|
36 |
+
credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
|
37 |
+
if credentials:
|
38 |
+
if not credentials.scheme == "Bearer":
|
39 |
+
raise HTTPException(status_code=403, detail="Invalid authentication scheme.")
|
40 |
+
else:
|
41 |
+
is_valid = JWTBearer.token_validation(credentials.credentials)
|
42 |
+
if not is_valid:
|
43 |
+
raise HTTPException(status_code=403, detail="Invalid token or expired token.")
|
44 |
+
return credentials.credentials
|
45 |
+
else:
|
46 |
+
raise HTTPException(status_code=403, detail="Invalid authorization code.")
|
47 |
+
|
48 |
+
@staticmethod
|
49 |
+
def token_validation(token: str) -> bool:
|
50 |
+
"""Decodes JWTs to check their validity by inspecting expiry and
|
51 |
+
authorization code.
|
52 |
+
|
53 |
+
Args:
|
54 |
+
token: str. Authenticated `access_token` of the user.
|
55 |
+
|
56 |
+
Returns:
|
57 |
+
bool value to indicate validity of the access tokens.
|
58 |
+
|
59 |
+
Raises:
|
60 |
+
jwt.JWTError: If decode fails.
|
61 |
+
ValidationError: If JWTs are not in RFC 7519 standard.
|
62 |
+
"""
|
63 |
+
try:
|
64 |
+
payload = jwt.decode(
|
65 |
+
token, config.JWT_SECRET_KEY, algorithms=[config.ALGORITHM]
|
66 |
+
)
|
67 |
+
token_data = TokenPayload(**payload)
|
68 |
+
|
69 |
+
if datetime.fromtimestamp(token_data.exp) < datetime.now():
|
70 |
+
return False
|
71 |
+
|
72 |
+
except(jwt.JWTError, ValidationError):
|
73 |
+
return False
|
74 |
+
|
75 |
+
return True
|
TechdocsAPI/backend/services/auth/utils/auth_funcs.py
ADDED
@@ -0,0 +1,171 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""Utility class to leverage encryption, verification of entered credentials
|
2 |
+
and generation of JWT access tokens.
|
3 |
+
"""
|
4 |
+
from datetime import datetime, timedelta
|
5 |
+
from typing import Union, Any
|
6 |
+
import secrets
|
7 |
+
|
8 |
+
from jose import jwt
|
9 |
+
from passlib.context import CryptContext
|
10 |
+
from pydantic import ValidationError
|
11 |
+
|
12 |
+
from fastapi.exceptions import HTTPException
|
13 |
+
|
14 |
+
from backend.core.ConfigEnv import config
|
15 |
+
from backend.core.Exceptions import *
|
16 |
+
from backend.models import TokenPayload, TokenSchema
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
ACCESS_TOKEN_EXPIRE_MINUTES = 30 # 30 minutes
|
21 |
+
REFRESH_TOKEN_EXPIRE_MINUTES = 60 * 24 * 3 # 3 days
|
22 |
+
|
23 |
+
|
24 |
+
class Auth:
|
25 |
+
"""Utility class to perform - 1.encryption via `bcrypt` scheme.
|
26 |
+
2.password hashing 3.verification of credentials and generating
|
27 |
+
access tokens.
|
28 |
+
|
29 |
+
Attrs:
|
30 |
+
pwd_context: CryptContext. Helper for hashing & verifying passwords
|
31 |
+
using `bcrypt` algorithm.
|
32 |
+
"""
|
33 |
+
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
|
34 |
+
|
35 |
+
|
36 |
+
|
37 |
+
@classmethod
|
38 |
+
def get_password_hash(cls,password: str) -> str:
|
39 |
+
"""Encrypts the entered password.
|
40 |
+
|
41 |
+
Args:
|
42 |
+
password: str. Entered password.
|
43 |
+
|
44 |
+
Returns:
|
45 |
+
returns hashed(encrypted) password string.
|
46 |
+
"""
|
47 |
+
return cls.pwd_context.hash(password)
|
48 |
+
|
49 |
+
@classmethod
|
50 |
+
def verify_password(cls, plain_password: str, hashed_password: str) -> bool:
|
51 |
+
"""Validates if the entered password matches the actual password.
|
52 |
+
|
53 |
+
Args:
|
54 |
+
plain_password: str. Entered password by user.
|
55 |
+
hashed_password: str. hashed password from the database.
|
56 |
+
|
57 |
+
Returns:
|
58 |
+
bool value indicating whether the passwords match or not.
|
59 |
+
"""
|
60 |
+
return cls.pwd_context.verify(plain_password, hashed_password)
|
61 |
+
|
62 |
+
@staticmethod
|
63 |
+
def verify_username(entered_username: str, db_username: str) -> bool:
|
64 |
+
"""Validates if the entered username matches the actual username.
|
65 |
+
|
66 |
+
Args:
|
67 |
+
entered_username: str. Entered `username` by user.
|
68 |
+
db_username: str. username from the database.
|
69 |
+
|
70 |
+
Returns:
|
71 |
+
bool value indicating whether the village names match or not.
|
72 |
+
"""
|
73 |
+
return entered_username == db_username
|
74 |
+
|
75 |
+
@staticmethod
|
76 |
+
def create_access_token(subject: Union[str, Any], expires_delta: int = None) -> str:
|
77 |
+
"""Creates JWT access token.
|
78 |
+
|
79 |
+
Args:
|
80 |
+
subject: Union[Any, str]. Hash_key to generate access token from.
|
81 |
+
expires_delta: int = None. Expiry time for the JWT.
|
82 |
+
|
83 |
+
Returns:
|
84 |
+
encoded_jwt: str. Encoded JWT token from the subject of interest.
|
85 |
+
"""
|
86 |
+
if expires_delta is not None:
|
87 |
+
expires_delta = datetime.utcnow() + expires_delta
|
88 |
+
else:
|
89 |
+
expires_delta = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
|
90 |
+
|
91 |
+
to_encode = {"exp": expires_delta, "sub": str(subject)}
|
92 |
+
encoded_jwt = jwt.encode(to_encode, config.JWT_SECRET_KEY, config.ALGORITHM)
|
93 |
+
return encoded_jwt
|
94 |
+
|
95 |
+
@staticmethod
|
96 |
+
def create_refresh_token(subject: Union[str, Any], expires_delta: int = None) -> str:
|
97 |
+
"""Creates JWT refresh access token.
|
98 |
+
|
99 |
+
Args:
|
100 |
+
subject: Union[Any, str]. Hash_key to generate access token from.
|
101 |
+
expires_delta: int = None. Expiry time for the JWT.
|
102 |
+
|
103 |
+
Returns:
|
104 |
+
encoded_jwt: str. Encoded JWT token from the subject of interest.
|
105 |
+
"""
|
106 |
+
if expires_delta is not None:
|
107 |
+
expires_delta = datetime.utcnow() + expires_delta
|
108 |
+
else:
|
109 |
+
expires_delta = datetime.utcnow() + timedelta(minutes=REFRESH_TOKEN_EXPIRE_MINUTES)
|
110 |
+
|
111 |
+
to_encode = {"exp": expires_delta, "sub": str(subject)}
|
112 |
+
encoded_jwt = jwt.encode(to_encode, config.JWT_REFRESH_SECRET_KEY, config.ALGORITHM)
|
113 |
+
return encoded_jwt
|
114 |
+
|
115 |
+
@staticmethod
|
116 |
+
def generate_access_tokens_from_refresh_tokens(token: str) -> TokenSchema:
|
117 |
+
"""Generates a new pair of tokens by implementing rotating
|
118 |
+
refresh_access_tokens.
|
119 |
+
|
120 |
+
Args:
|
121 |
+
token: str. Current valid refresh access token.
|
122 |
+
|
123 |
+
Returns:
|
124 |
+
tokens: TokenSchema. New tokens with new validity.
|
125 |
+
|
126 |
+
Raises:
|
127 |
+
LoginFailedException: If the current refresh access token is
|
128 |
+
invalid.
|
129 |
+
"""
|
130 |
+
tokens = TokenSchema.get_instance(
|
131 |
+
access_token= "",
|
132 |
+
refresh_token= "",
|
133 |
+
)
|
134 |
+
try:
|
135 |
+
payload = jwt.decode(
|
136 |
+
token, config.JWT_REFRESH_SECRET_KEY, algorithms=[config.ALGORITHM]
|
137 |
+
)
|
138 |
+
token_data = TokenPayload(**payload)
|
139 |
+
if datetime.fromtimestamp(token_data.exp)< datetime.now():
|
140 |
+
raise HTTPException(status_code=403, detail="Invalid token or expired token.")
|
141 |
+
except (jwt.JWTError, ValidationError):
|
142 |
+
raise InvalidCredentialsException(tokens)
|
143 |
+
tokens['access_token'] = Auth.create_access_token(token_data.sub)
|
144 |
+
tokens['refresh_token'] = Auth.create_refresh_token(token_data.sub)
|
145 |
+
tokens['status'] = 'login successful'
|
146 |
+
tokens['role'] = token_data.sub.split("_")[1]
|
147 |
+
return tokens
|
148 |
+
|
149 |
+
@classmethod
|
150 |
+
def generate_api_key(cls, username: str):
|
151 |
+
return cls.get_password_hash(username + secrets.token_urlsafe(25 - len(username)))
|
152 |
+
|
153 |
+
@classmethod
|
154 |
+
def get_user_credentials(cls,access_token:str):
|
155 |
+
response_result = GeneralResponse.get_instance(data={},
|
156 |
+
status="not_allowed",
|
157 |
+
message=["Not authenticated"]
|
158 |
+
)
|
159 |
+
try:
|
160 |
+
payload = jwt.decode(
|
161 |
+
access_token, config.JWT_SECRET_KEY, algorithms=[config.ALGORITHM]
|
162 |
+
)
|
163 |
+
token_data = TokenPayload(**payload)
|
164 |
+
return token_data.sub
|
165 |
+
except (jwt.JWTError, ValidationError):
|
166 |
+
raise InvalidCredentialsException(response_result)
|
167 |
+
|
168 |
+
@classmethod
|
169 |
+
def verify_apikey(cls,user_api_key:str,true_api_key:str):
|
170 |
+
return user_api_key == true_api_key
|
171 |
+
|
TechdocsAPI/backend/services/db/__init__.py
ADDED
File without changes
|
TechdocsAPI/backend/services/db/utils/DBQueries.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# fix ObjectId & FastApi conflict
|
2 |
+
import pydantic
|
3 |
+
from bson.objectid import ObjectId
|
4 |
+
pydantic.json.ENCODERS_BY_TYPE[ObjectId]=str
|
5 |
+
|
6 |
+
from typing import Union, Tuple, List
|
7 |
+
|
8 |
+
from backend.utils import DBConnection
|
9 |
+
from backend.core.Exceptions import *
|
10 |
+
|
11 |
+
|
12 |
+
class DBQueries:
|
13 |
+
@classmethod
|
14 |
+
def insert_to_database(cls, table_name:str, data:Union[Tuple, List[Tuple]], cols:List[str]=None):
|
15 |
+
con = DBConnection.get_client()
|
16 |
+
cursor = con.cursor()
|
17 |
+
QUERY = ('INSERT INTO {table_name} '
|
18 |
+
f'({",".join(cols)}) '
|
19 |
+
'VALUES '
|
20 |
+
).format(table_name=table_name)
|
21 |
+
print(data)
|
22 |
+
if isinstance(data, list):
|
23 |
+
QUERY+="("+",".join(["%s" for _ in range(len(data[0]))])+")"
|
24 |
+
cursor.executemany(QUERY, data)
|
25 |
+
else:
|
26 |
+
QUERY+="("+",".join(["%s" for _ in range(len(data))])+")"
|
27 |
+
cursor.execute(QUERY, data)
|
28 |
+
con.commit()
|
29 |
+
|
30 |
+
@classmethod
|
31 |
+
def fetch_data_from_database(cls,table_name:str,cols_to_fetch:Union[str, List[str]], where_clause:str=None):
|
32 |
+
con = DBConnection.get_client()
|
33 |
+
cursor = con.cursor()
|
34 |
+
if isinstance(cols_to_fetch, str):
|
35 |
+
cols_to_fetch = [cols_to_fetch]
|
36 |
+
cols_to_fetch = ", ".join(cols_to_fetch)
|
37 |
+
QUERY = ('SELECT {cols} FROM {table_name}').format(cols=cols_to_fetch, table_name=table_name)
|
38 |
+
if where_clause:
|
39 |
+
QUERY = QUERY + " WHERE " + where_clause
|
40 |
+
cursor.execute(QUERY)
|
41 |
+
return cursor.fetchall()
|
42 |
+
|
43 |
+
@classmethod
|
44 |
+
def update_data_in_database(cls, table_name:str, cols_to_update:Union[str, List[str]], where_clause:str=None, new_values:Union[str, List[str]]=None):
|
45 |
+
con = DBConnection.get_client()
|
46 |
+
cursor = con.cursor()
|
47 |
+
if isinstance(cols_to_update, str):
|
48 |
+
cols_to_update = cols_to_update + "=%s"
|
49 |
+
else:
|
50 |
+
cols_to_update = "=%s, ".join(cols_to_update)
|
51 |
+
|
52 |
+
if isinstance(new_values, str):
|
53 |
+
new_values = [new_values]
|
54 |
+
|
55 |
+
QUERY = ('UPDATE {table_name} SET {cols}').format(table_name=table_name, cols=cols_to_update)
|
56 |
+
if where_clause:
|
57 |
+
QUERY = QUERY + " WHERE " + where_clause
|
58 |
+
cursor.execute(QUERY, new_values)
|
59 |
+
con.commit()
|
60 |
+
return True
|
61 |
+
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
|
TechdocsAPI/backend/utils/DBConnection.py
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
""" Import Important Packages"""
|
2 |
+
import mysql.connector
|
3 |
+
|
4 |
+
from backend.core.ConfigEnv import config
|
5 |
+
|
6 |
+
|
7 |
+
class DBConnection:
|
8 |
+
"""DBConnection Class. It ensures only one instance of the class is
|
9 |
+
created and it is accessible from everywhere. It is used in the
|
10 |
+
design of logging classes, Configuration classes where we need to have
|
11 |
+
only one instance of the class. There is no need to create multiple
|
12 |
+
instances of each operation across all components of application.
|
13 |
+
|
14 |
+
Raises:
|
15 |
+
Exception: It raises an exception if the client instance is not created.
|
16 |
+
"""
|
17 |
+
__client = None #This is the client variable that is used to connect to the database
|
18 |
+
_flag = False
|
19 |
+
def __init__(self):
|
20 |
+
"""This is the constructor of the class. It is used to create the client
|
21 |
+
variable. It also checks if the client instance is already created.
|
22 |
+
If the client instance is already created, then it does not create a
|
23 |
+
new client instance.
|
24 |
+
"""
|
25 |
+
if DBConnection.__client is not None:
|
26 |
+
raise Exception("This class is a singleton!")
|
27 |
+
else:
|
28 |
+
creds={
|
29 |
+
'host':config.HOSTNAME,
|
30 |
+
'user':config.UID,
|
31 |
+
'password':config.PASSWORD,
|
32 |
+
'database':config.DATABASE
|
33 |
+
}
|
34 |
+
DBConnection.__client = mysql.connector.connect(**creds)
|
35 |
+
DBConnection._flag = True
|
36 |
+
|
37 |
+
@staticmethod # A static method is a method that is called without creating an instance of the class.
|
38 |
+
def get_client():
|
39 |
+
"""The get_client() function is used to get the client instance.
|
40 |
+
|
41 |
+
Returns:
|
42 |
+
DBConnection.__client: It returns the client instance.
|
43 |
+
"""
|
44 |
+
return DBConnection.__client
|
45 |
+
|
46 |
+
@classmethod
|
47 |
+
def is_connected(cls)->bool:
|
48 |
+
"""property to get the database connection flag.
|
49 |
+
Returns:
|
50 |
+
DBConnection._flag: bool. Connection status to the DB.
|
51 |
+
"""
|
52 |
+
return cls._flag
|
53 |
+
|
54 |
+
|
55 |
+
|
56 |
+
|
57 |
+
|
TechdocsAPI/backend/utils/__init__.py
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
from .DBConnection import DBConnection
|
TechdocsAPI/backend/utils/prompt.txt
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
You are an AI Coding Assitant and your task is to generate an elaborate, high quality docstring for the query function given by the user. A docstring consists of the following sections:
|
2 |
+
1. Description: Is the description of what the function does.
|
3 |
+
2. Arguments:
|
4 |
+
1. Argument Name: Description of the argument and its type.
|
5 |
+
3. Returns: Description of the return value of the function if any.
|
6 |
+
4. Raises: Description of the errors that can be raised by the function if any.
|
7 |
+
|
8 |
+
Instruction: {instruction}
|
9 |
+
|
10 |
+
Your task is to generate a docstring for the above query.
|
11 |
+
Response:
|
TechdocsAPI/backend/utils/scopes.py
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
from typing import Callable
|
2 |
+
|
3 |
+
from backend.models import User
|
TechdocsAPI/requirements.txt
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
fastapi==0.99.1
|
2 |
+
uvicorn
|
3 |
+
requests
|
4 |
+
pydantic==1.10.12
|
5 |
+
python-jose[cryptography]
|
6 |
+
passlib[bcrypt]
|
7 |
+
mysql-connector-python
|
8 |
+
pydantic[email]
|
9 |
+
langchain
|
10 |
+
clarifai
|
Login.py β frontend/Login.py
RENAMED
@@ -6,7 +6,7 @@ import streamlit as st
|
|
6 |
|
7 |
def auth_page():
|
8 |
|
9 |
-
base_url = '
|
10 |
|
11 |
|
12 |
headers={"accept":"application/json"}
|
|
|
6 |
|
7 |
def auth_page():
|
8 |
|
9 |
+
base_url = 'http://localhost:8000'
|
10 |
|
11 |
|
12 |
headers={"accept":"application/json"}
|
{pages β frontend/pages}/Code.py
RENAMED
@@ -28,7 +28,7 @@ with st.sidebar:
|
|
28 |
if st.button("Generate API KEY"):
|
29 |
with st.spinner("Generating API Key..."):
|
30 |
try:
|
31 |
-
base_url = "
|
32 |
headers={"accept":"application/json", "Authorization": f"Bearer {st.session_state.access_token}"}
|
33 |
response = requests.put(url=base_url + "/auth/regenerate_api_key", headers=headers, data=json.dumps({"username":st.session_state.username}))
|
34 |
if (response.status_code!=200):
|
@@ -48,7 +48,7 @@ with st.sidebar:
|
|
48 |
|
49 |
|
50 |
def code_page():
|
51 |
-
base_url = '
|
52 |
|
53 |
def query_post(url, headers, data=None, params=None):
|
54 |
response = requests.post(url, data=data, headers=headers, params=params)
|
|
|
28 |
if st.button("Generate API KEY"):
|
29 |
with st.spinner("Generating API Key..."):
|
30 |
try:
|
31 |
+
base_url = "http://localhost:8000"
|
32 |
headers={"accept":"application/json", "Authorization": f"Bearer {st.session_state.access_token}"}
|
33 |
response = requests.put(url=base_url + "/auth/regenerate_api_key", headers=headers, data=json.dumps({"username":st.session_state.username}))
|
34 |
if (response.status_code!=200):
|
|
|
48 |
|
49 |
|
50 |
def code_page():
|
51 |
+
base_url = 'http://localhost:8000'
|
52 |
|
53 |
def query_post(url, headers, data=None, params=None):
|
54 |
response = requests.post(url, data=data, headers=headers, params=params)
|
requirements.txt β frontend/requirements.txt
RENAMED
File without changes
|
π‘_Home.py β frontend/π‘_Home.py
RENAMED
@@ -7,7 +7,7 @@ import base64
|
|
7 |
|
8 |
# image2=Image.open('assets/logo2.png')
|
9 |
st.set_page_config(
|
10 |
-
page_title="
|
11 |
layout="wide",
|
12 |
page_icon="π‘",
|
13 |
initial_sidebar_state="expanded",
|
|
|
7 |
|
8 |
# image2=Image.open('assets/logo2.png')
|
9 |
st.set_page_config(
|
10 |
+
page_title="Techdocs",
|
11 |
layout="wide",
|
12 |
page_icon="π‘",
|
13 |
initial_sidebar_state="expanded",
|