Spaces:
Runtime error
Runtime error
feat: Chats & FD services
Browse files- .gitignore +1 -0
- README.md +66 -0
- apps/apis/chats/__init__.py +57 -14
- apps/apis/chats/controllers/conversation_storage.py +43 -0
- apps/apis/chats/controllers/openai_controller.py +37 -0
- apps/apis/chats/models/chats_model.py +5 -0
- apps/apis/fd/__init__.py +30 -3
- apps/apis/fd/controllers/fd_controller.py +32 -0
- apps/apis/fd/models/fd_model.py +8 -0
- apps/services/foward/fw_middleware.py +6 -2
- apps/services/foward/fw_storage.py +5 -4
- data/.gitkeep +0 -0
- main.py +0 -1
- requirements.txt +0 -0
- resources/.gitkeep +0 -0
- resources/fd_model.tflite +0 -0
- utils/constants.py +2 -0
- utils/local_storage.py +10 -10
.gitignore
CHANGED
@@ -2,6 +2,7 @@ env/
|
|
2 |
__pycache__/
|
3 |
.env
|
4 |
temp/*
|
|
|
5 |
|
6 |
# Keep the .gitkeep file in the temp/ directory
|
7 |
!.gitkeep
|
|
|
2 |
__pycache__/
|
3 |
.env
|
4 |
temp/*
|
5 |
+
data/*
|
6 |
|
7 |
# Keep the .gitkeep file in the temp/ directory
|
8 |
!.gitkeep
|
README.md
CHANGED
@@ -41,6 +41,14 @@ curl --location 'https://{domain}/service/fw/' --request 'POST' --data '{"url":"
|
|
41 |
curl --location 'https://{domain}/service/fw/' --request 'DELETE' --data '{"index":0}'
|
42 |
```
|
43 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
### Children Server Endpoint Request & Response
|
45 |
|
46 |
- `/api/rembg/`
|
@@ -59,6 +67,64 @@ curl --location 'https://{domain}/service/fw/' --request 'DELETE' --data '{"inde
|
|
59 |
}
|
60 |
```
|
61 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
62 |
## 😊 Contributors
|
63 |
|
64 |
- GDSC-FPTU [[gdsc-fptu](https://github.com/gdsc-fptu)]
|
|
|
41 |
curl --location 'https://{domain}/service/fw/' --request 'DELETE' --data '{"index":0}'
|
42 |
```
|
43 |
|
44 |
+
### Server Health Checker
|
45 |
+
|
46 |
+
```bash
|
47 |
+
curl --location '{children-base-domain}/health'
|
48 |
+
```
|
49 |
+
|
50 |
+
This route checks the health status of children server. The children is considered as good health when it return anything with status 200.
|
51 |
+
|
52 |
### Children Server Endpoint Request & Response
|
53 |
|
54 |
- `/api/rembg/`
|
|
|
67 |
}
|
68 |
```
|
69 |
|
70 |
+
- `/api/fd/`
|
71 |
+
|
72 |
+
```json
|
73 |
+
// Request. Form-data
|
74 |
+
{
|
75 |
+
"image": "<image-data"
|
76 |
+
}
|
77 |
+
|
78 |
+
// Response. JSON
|
79 |
+
{
|
80 |
+
"data": {
|
81 |
+
"faces": []
|
82 |
+
}
|
83 |
+
}
|
84 |
+
```
|
85 |
+
|
86 |
+
- `/api/chats/`
|
87 |
+
|
88 |
+
```json
|
89 |
+
// Request. JSON
|
90 |
+
{
|
91 |
+
"prompt": "A Prompt from user"
|
92 |
+
}
|
93 |
+
|
94 |
+
// Response. JSON
|
95 |
+
{
|
96 |
+
"data": {
|
97 |
+
"message": "A Message from AI"
|
98 |
+
}
|
99 |
+
}
|
100 |
+
```
|
101 |
+
|
102 |
+
- `/api/chats/:id`
|
103 |
+
|
104 |
+
```json
|
105 |
+
// Request. JSON
|
106 |
+
{
|
107 |
+
"prompt": "A Prompt from user",
|
108 |
+
"conversation": [
|
109 |
+
{
|
110 |
+
"role": "user",
|
111 |
+
"content": "Message A"
|
112 |
+
},
|
113 |
+
{
|
114 |
+
"role": "assistant",
|
115 |
+
"content": "Message B"
|
116 |
+
}
|
117 |
+
]
|
118 |
+
}
|
119 |
+
|
120 |
+
// Response. JSON
|
121 |
+
{
|
122 |
+
"data": {
|
123 |
+
"message": "A Message from AI"
|
124 |
+
}
|
125 |
+
}
|
126 |
+
```
|
127 |
+
|
128 |
## 😊 Contributors
|
129 |
|
130 |
- GDSC-FPTU [[gdsc-fptu](https://github.com/gdsc-fptu)]
|
apps/apis/chats/__init__.py
CHANGED
@@ -1,6 +1,10 @@
|
|
1 |
-
|
|
|
2 |
from fastapi.responses import JSONResponse
|
3 |
-
from
|
|
|
|
|
|
|
4 |
|
5 |
router = APIRouter(prefix='/chats')
|
6 |
router_base_configs = {
|
@@ -10,24 +14,63 @@ router_base_configs = {
|
|
10 |
|
11 |
|
12 |
# Message
|
13 |
-
@router.post("
|
14 |
-
def message():
|
15 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
16 |
|
|
|
|
|
17 |
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
|
24 |
# Create conversation
|
25 |
-
@router.
|
26 |
def create_conversation():
|
27 |
-
|
|
|
28 |
|
29 |
|
30 |
# Delete conversation
|
31 |
-
@router.delete("/delete", **router_base_configs)
|
32 |
-
def delete_conversation():
|
33 |
-
|
|
|
|
1 |
+
import os
|
2 |
+
from fastapi import APIRouter, HTTPException, Depends
|
3 |
from fastapi.responses import JSONResponse
|
4 |
+
from .models.chats_model import ChatsModel
|
5 |
+
from .controllers.conversation_storage import is_conversation_storage_exist, get_conversation_storage, create_conversation_storage, delete_conversation_storage, update_conversation_storage
|
6 |
+
from .controllers.openai_controller import send_message, send_message_conversation
|
7 |
+
from apps.services.foward.fw_middleware import forward_request, forward_middleware
|
8 |
|
9 |
router = APIRouter(prefix='/chats')
|
10 |
router_base_configs = {
|
|
|
14 |
|
15 |
|
16 |
# Message
|
17 |
+
@router.post("/", **router_base_configs)
|
18 |
+
def message(data: ChatsModel, fw_index=Depends(forward_middleware)):
|
19 |
+
# Forward request
|
20 |
+
fw_data = {
|
21 |
+
"data": {"prompt": data.prompt}
|
22 |
+
}
|
23 |
+
fw_response = forward_request(fw_index, fw_data, '/api/chats/')
|
24 |
+
if fw_response is not None:
|
25 |
+
return {"message": fw_response["data"]["message"]}
|
26 |
|
27 |
+
response = send_message(data.prompt)
|
28 |
+
return {"message": response}
|
29 |
|
30 |
+
|
31 |
+
# Message to conversation
|
32 |
+
@router.post("/{cid}", **router_base_configs)
|
33 |
+
def conversation(cid: str, data: ChatsModel, fw_index=Depends(forward_middleware)):
|
34 |
+
is_exist = is_conversation_storage_exist(cid)
|
35 |
+
if not is_exist:
|
36 |
+
raise HTTPException(status_code=404, detail="Conversation not found")
|
37 |
+
|
38 |
+
# Forward request
|
39 |
+
fw_data = {
|
40 |
+
"data": {"prompt": data.prompt, "conversation": get_conversation_storage(cid)}
|
41 |
+
}
|
42 |
+
fw_response = forward_request(fw_index, fw_data, f'/api/chats/{cid}')
|
43 |
+
if fw_response is not None:
|
44 |
+
# Update conversation
|
45 |
+
update_conversation_storage(cid, "user", data.prompt)
|
46 |
+
update_conversation_storage(
|
47 |
+
cid, "assistant", fw_response["data"]["message"])
|
48 |
+
return {"message": fw_response["data"]["message"]}
|
49 |
+
|
50 |
+
response = send_message_conversation(cid, data.prompt)
|
51 |
+
return {"message": response}
|
52 |
+
|
53 |
+
|
54 |
+
# Get conversation by id
|
55 |
+
@router.get("/{cid}", **router_base_configs)
|
56 |
+
def get_conversation(cid: str):
|
57 |
+
is_exist = is_conversation_storage_exist(cid)
|
58 |
+
if not is_exist:
|
59 |
+
raise HTTPException(status_code=404, detail="Conversation not found")
|
60 |
+
|
61 |
+
conversation = get_conversation_storage(cid)
|
62 |
+
return {"conversation": conversation}
|
63 |
|
64 |
|
65 |
# Create conversation
|
66 |
+
@router.get("/create", **router_base_configs)
|
67 |
def create_conversation():
|
68 |
+
cid = create_conversation_storage()
|
69 |
+
return {"conversation_id": cid}
|
70 |
|
71 |
|
72 |
# Delete conversation
|
73 |
+
@router.delete("/delete/{cid}", **router_base_configs)
|
74 |
+
def delete_conversation(cid: str):
|
75 |
+
delete_conversation_storage(cid)
|
76 |
+
return {"conversation_id": cid}
|
apps/apis/chats/controllers/conversation_storage.py
ADDED
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import uuid
|
2 |
+
from utils.local_storage import read_from_local, save_to_local, remove_from_local
|
3 |
+
from utils.constants import DATA_DIR
|
4 |
+
|
5 |
+
|
6 |
+
def is_conversation_storage_exist(id: str) -> bool:
|
7 |
+
# Check if conversation exist
|
8 |
+
return read_from_local(f"{id}.json", DATA_DIR) is not None
|
9 |
+
|
10 |
+
|
11 |
+
def get_conversation_storage(id: str) -> list:
|
12 |
+
# Get conversation
|
13 |
+
conversation = read_from_local(f"{id}.json", DATA_DIR)
|
14 |
+
# Return conversation
|
15 |
+
return conversation
|
16 |
+
|
17 |
+
|
18 |
+
def create_conversation_storage() -> str:
|
19 |
+
# Generate conversation id
|
20 |
+
conversation_id = str(uuid.uuid4())
|
21 |
+
# Save to local
|
22 |
+
save_to_local([], f"{conversation_id}.json", False, DATA_DIR)
|
23 |
+
# Return conversation id
|
24 |
+
return conversation_id
|
25 |
+
|
26 |
+
|
27 |
+
def update_conversation_storage(id: str, role: str, message: str) -> list:
|
28 |
+
# Get conversation
|
29 |
+
conversation = get_conversation_storage(id)
|
30 |
+
# Append new message
|
31 |
+
conversation.append({
|
32 |
+
"role": role,
|
33 |
+
"content": message
|
34 |
+
})
|
35 |
+
# Save to local
|
36 |
+
save_to_local(conversation, f"{id}.json", False, DATA_DIR)
|
37 |
+
# Return conversation
|
38 |
+
return conversation
|
39 |
+
|
40 |
+
|
41 |
+
def delete_conversation_storage(id: str):
|
42 |
+
# Delete conversation
|
43 |
+
remove_from_local(f"{id}.json", DATA_DIR)
|
apps/apis/chats/controllers/openai_controller.py
ADDED
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from openai import OpenAI
|
3 |
+
from .conversation_storage import get_conversation_storage, update_conversation_storage
|
4 |
+
|
5 |
+
|
6 |
+
BASE_ENHANCE_PROMPT = {
|
7 |
+
"role": "system", "content": "You are a helpful assistant. You are helping a customer to solve a problem."}
|
8 |
+
|
9 |
+
|
10 |
+
client = OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
11 |
+
|
12 |
+
|
13 |
+
def send_message(prompt: str):
|
14 |
+
return client.chat.completions.create(
|
15 |
+
model="gpt-3.5-turbo",
|
16 |
+
messages=[
|
17 |
+
BASE_ENHANCE_PROMPT,
|
18 |
+
{"role": "user", "content": prompt}
|
19 |
+
]
|
20 |
+
).choices[0].message.content
|
21 |
+
|
22 |
+
|
23 |
+
def send_message_conversation(conversation_id: str, prompt: str):
|
24 |
+
# Update conversation
|
25 |
+
update_conversation_storage(conversation_id, "user", prompt)
|
26 |
+
# Generate response
|
27 |
+
response = client.chat.completions.create(
|
28 |
+
model="gpt-3.5-turbo",
|
29 |
+
messages=[
|
30 |
+
BASE_ENHANCE_PROMPT,
|
31 |
+
*get_conversation_storage(conversation_id),
|
32 |
+
{"role": "user", "content": prompt}
|
33 |
+
]
|
34 |
+
).choices[0].message.content
|
35 |
+
# Update conversation
|
36 |
+
update_conversation_storage(conversation_id, "assistant", response)
|
37 |
+
return response
|
apps/apis/chats/models/chats_model.py
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pydantic import BaseModel, Field
|
2 |
+
|
3 |
+
|
4 |
+
class ChatsModel(BaseModel):
|
5 |
+
prompt: str = Field(..., example="Hello, I'm a chatbot")
|
apps/apis/fd/__init__.py
CHANGED
@@ -1,5 +1,9 @@
|
|
1 |
-
from fastapi import APIRouter
|
2 |
from fastapi.responses import JSONResponse
|
|
|
|
|
|
|
|
|
3 |
|
4 |
router = APIRouter(prefix='/fd')
|
5 |
router_base_configs = {
|
@@ -10,5 +14,28 @@ router_base_configs = {
|
|
10 |
|
11 |
# Face detection
|
12 |
@router.post("/", **router_base_configs)
|
13 |
-
def faces_detection(
|
14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import APIRouter, Depends, HTTPException
|
2 |
from fastapi.responses import JSONResponse
|
3 |
+
from apps.services.foward.fw_middleware import forward_request, forward_middleware
|
4 |
+
from .models.fd_model import FaceDetectionModel
|
5 |
+
from .controllers.fd_controller import faces_detection_controller
|
6 |
+
|
7 |
|
8 |
router = APIRouter(prefix='/fd')
|
9 |
router_base_configs = {
|
|
|
14 |
|
15 |
# Face detection
|
16 |
@router.post("/", **router_base_configs)
|
17 |
+
async def faces_detection(
|
18 |
+
image: FaceDetectionModel.image = FaceDetectionModel.image_default,
|
19 |
+
fw_index: FaceDetectionModel.fw_index = Depends(forward_middleware)
|
20 |
+
):
|
21 |
+
# Forward request
|
22 |
+
fw_data = {
|
23 |
+
"files": {"image": image.file}
|
24 |
+
}
|
25 |
+
fw_response = forward_request(fw_index, fw_data, '/api/fd/')
|
26 |
+
if fw_response is not None:
|
27 |
+
return JSONResponse({
|
28 |
+
"faces": fw_response["data"]["faces"]
|
29 |
+
})
|
30 |
+
|
31 |
+
# Check if image is None
|
32 |
+
if image is None:
|
33 |
+
raise HTTPException(status_code=400, detail="Image is required")
|
34 |
+
# Check if image is empty
|
35 |
+
if image.filename == '':
|
36 |
+
raise HTTPException(status_code=400, detail="Image is empty")
|
37 |
+
# Read image
|
38 |
+
image_bytes = await image.read()
|
39 |
+
# Process image
|
40 |
+
detected_faces = faces_detection_controller(image_bytes)
|
41 |
+
return JSONResponse({"faces": detected_faces})
|
apps/apis/fd/controllers/fd_controller.py
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import numpy as np
|
2 |
+
import cv2 as cv
|
3 |
+
import mediapipe as mp
|
4 |
+
from mediapipe.tasks import python
|
5 |
+
from mediapipe.tasks.python import vision
|
6 |
+
|
7 |
+
base_options = python.BaseOptions(model_asset_path='resources/fd_model.tflite')
|
8 |
+
options = vision.FaceDetectorOptions(base_options=base_options)
|
9 |
+
detector = vision.FaceDetector.create_from_options(options)
|
10 |
+
|
11 |
+
|
12 |
+
def format_detections(detection_result):
|
13 |
+
faces = []
|
14 |
+
for detection in detection_result.detections:
|
15 |
+
face = {
|
16 |
+
"bbox": {
|
17 |
+
"x": detection.bounding_box.origin_x,
|
18 |
+
"y": detection.bounding_box.origin_y,
|
19 |
+
"width": detection.bounding_box.width,
|
20 |
+
"height": detection.bounding_box.height,
|
21 |
+
},
|
22 |
+
}
|
23 |
+
faces.append(face)
|
24 |
+
return faces
|
25 |
+
|
26 |
+
|
27 |
+
def faces_detection_controller(image: bytes):
|
28 |
+
cv_image = cv.imdecode(np.frombuffer(image, np.uint8), cv.IMREAD_COLOR)
|
29 |
+
mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=cv_image)
|
30 |
+
# Process image
|
31 |
+
detection_result = detector.detect(mp_image)
|
32 |
+
return format_detections(detection_result)
|
apps/apis/fd/models/fd_model.py
ADDED
@@ -0,0 +1,8 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from fastapi import File, UploadFile
|
2 |
+
|
3 |
+
|
4 |
+
class FaceDetectionModel:
|
5 |
+
image = UploadFile | None
|
6 |
+
image_default = File(
|
7 |
+
None, description="Image for face detection", example="image.jpg")
|
8 |
+
fw_index = int | None
|
apps/services/foward/fw_middleware.py
CHANGED
@@ -18,7 +18,7 @@ async def verify_fw_resources(url: str) -> bool:
|
|
18 |
async def forward_middleware(fw: str = None):
|
19 |
# Verify forward destination index
|
20 |
try:
|
21 |
-
if fw != 'auto':
|
22 |
fw = int(fw)
|
23 |
except Exception:
|
24 |
raise HTTPException(
|
@@ -46,12 +46,16 @@ async def forward_middleware(fw: str = None):
|
|
46 |
fw = None
|
47 |
# If forward destination is not auto, update forward destination tasks
|
48 |
else:
|
49 |
-
|
|
|
50 |
|
51 |
return fw
|
52 |
|
53 |
|
54 |
def forward_request(fw_index: int, data: Any, endpoint: str = '', method: Literal['GET', 'POST', 'PUT', 'DELETE'] = 'POST'):
|
|
|
|
|
|
|
55 |
# Get forward destination url
|
56 |
fw_destinations = get_fw_destinations()
|
57 |
fw_url = fw_destinations[fw_index]['url'] + endpoint
|
|
|
18 |
async def forward_middleware(fw: str = None):
|
19 |
# Verify forward destination index
|
20 |
try:
|
21 |
+
if fw != 'auto' and fw is not None:
|
22 |
fw = int(fw)
|
23 |
except Exception:
|
24 |
raise HTTPException(
|
|
|
46 |
fw = None
|
47 |
# If forward destination is not auto, update forward destination tasks
|
48 |
else:
|
49 |
+
if fw is not None:
|
50 |
+
update_fw_destination(fw, fw_destinations[fw]['tasks'] + 1)
|
51 |
|
52 |
return fw
|
53 |
|
54 |
|
55 |
def forward_request(fw_index: int, data: Any, endpoint: str = '', method: Literal['GET', 'POST', 'PUT', 'DELETE'] = 'POST'):
|
56 |
+
# Return None if fw_index is None
|
57 |
+
if fw_index is None:
|
58 |
+
return None
|
59 |
# Get forward destination url
|
60 |
fw_destinations = get_fw_destinations()
|
61 |
fw_url = fw_destinations[fw_index]['url'] + endpoint
|
apps/services/foward/fw_storage.py
CHANGED
@@ -1,11 +1,12 @@
|
|
1 |
from utils.local_storage import read_from_local, save_to_local
|
|
|
2 |
|
3 |
|
4 |
FOWARD_JSON_FILE = 'forward.json'
|
5 |
|
6 |
|
7 |
def get_fw_destinations() -> list:
|
8 |
-
destinations = read_from_local(FOWARD_JSON_FILE)
|
9 |
if destinations is None:
|
10 |
return []
|
11 |
return destinations
|
@@ -23,7 +24,7 @@ def append_fw_destination(url: str):
|
|
23 |
"url": url
|
24 |
})
|
25 |
# Save to local
|
26 |
-
save_to_local(forward_destinations, FOWARD_JSON_FILE, False)
|
27 |
# Return index
|
28 |
return len(forward_destinations) - 1
|
29 |
|
@@ -34,7 +35,7 @@ def update_fw_destination(index: int, tasks: int):
|
|
34 |
# Update destination
|
35 |
forward_destinations[index]['tasks'] = tasks
|
36 |
# Save to local
|
37 |
-
save_to_local(forward_destinations, FOWARD_JSON_FILE, False)
|
38 |
|
39 |
|
40 |
def delete_fw_destination(index: int):
|
@@ -43,4 +44,4 @@ def delete_fw_destination(index: int):
|
|
43 |
# Delete destination
|
44 |
del forward_destinations[index]
|
45 |
# Save to local
|
46 |
-
save_to_local(forward_destinations, FOWARD_JSON_FILE, False)
|
|
|
1 |
from utils.local_storage import read_from_local, save_to_local
|
2 |
+
from utils.constants import DATA_DIR
|
3 |
|
4 |
|
5 |
FOWARD_JSON_FILE = 'forward.json'
|
6 |
|
7 |
|
8 |
def get_fw_destinations() -> list:
|
9 |
+
destinations = read_from_local(FOWARD_JSON_FILE, DATA_DIR)
|
10 |
if destinations is None:
|
11 |
return []
|
12 |
return destinations
|
|
|
24 |
"url": url
|
25 |
})
|
26 |
# Save to local
|
27 |
+
save_to_local(forward_destinations, FOWARD_JSON_FILE, False, DATA_DIR)
|
28 |
# Return index
|
29 |
return len(forward_destinations) - 1
|
30 |
|
|
|
35 |
# Update destination
|
36 |
forward_destinations[index]['tasks'] = tasks
|
37 |
# Save to local
|
38 |
+
save_to_local(forward_destinations, FOWARD_JSON_FILE, False, DATA_DIR)
|
39 |
|
40 |
|
41 |
def delete_fw_destination(index: int):
|
|
|
44 |
# Delete destination
|
45 |
del forward_destinations[index]
|
46 |
# Save to local
|
47 |
+
save_to_local(forward_destinations, FOWARD_JSON_FILE, False, DATA_DIR)
|
data/.gitkeep
ADDED
File without changes
|
main.py
CHANGED
@@ -2,7 +2,6 @@
|
|
2 |
import os
|
3 |
import uvicorn
|
4 |
from apps.create_app import create_app
|
5 |
-
from apps.services.foward.fw_middleware import forward_middleware
|
6 |
# Import routers
|
7 |
from apps.apis import router as api_router
|
8 |
from apps.services import router as service_router
|
|
|
2 |
import os
|
3 |
import uvicorn
|
4 |
from apps.create_app import create_app
|
|
|
5 |
# Import routers
|
6 |
from apps.apis import router as api_router
|
7 |
from apps.services import router as service_router
|
requirements.txt
CHANGED
Binary files a/requirements.txt and b/requirements.txt differ
|
|
resources/.gitkeep
ADDED
File without changes
|
resources/fd_model.tflite
ADDED
Binary file (230 kB). View file
|
|
utils/constants.py
CHANGED
@@ -4,6 +4,8 @@ APP_DOMAIN = "http://localhost:8000"
|
|
4 |
|
5 |
TEMP_DIR = os.path.join(os.getcwd(), 'temp')
|
6 |
|
|
|
|
|
7 |
DOC_TEMPLATE = f'''
|
8 |
<!DOCTYPE html>
|
9 |
<html>
|
|
|
4 |
|
5 |
TEMP_DIR = os.path.join(os.getcwd(), 'temp')
|
6 |
|
7 |
+
DATA_DIR = os.path.join(os.getcwd(), 'data')
|
8 |
+
|
9 |
DOC_TEMPLATE = f'''
|
10 |
<!DOCTYPE html>
|
11 |
<html>
|
utils/local_storage.py
CHANGED
@@ -31,7 +31,7 @@ def parse_filename(filename: str):
|
|
31 |
return filename
|
32 |
|
33 |
|
34 |
-
def save_to_local(file: bytes | Any, filename: str, is_parse_filename: bool = True):
|
35 |
# Parse filename
|
36 |
if is_parse_filename:
|
37 |
filename = parse_filename(filename)
|
@@ -43,7 +43,7 @@ def save_to_local(file: bytes | Any, filename: str, is_parse_filename: bool = Tr
|
|
43 |
else:
|
44 |
mode = 'wb'
|
45 |
# Save file
|
46 |
-
with open(os.path.join(
|
47 |
if file_extension == 'json':
|
48 |
json.dump(file, f)
|
49 |
else:
|
@@ -52,7 +52,7 @@ def save_to_local(file: bytes | Any, filename: str, is_parse_filename: bool = Tr
|
|
52 |
return f"{APP_DOMAIN}/static/{filename}"
|
53 |
|
54 |
|
55 |
-
def read_from_local(filename: str):
|
56 |
# Get type of file
|
57 |
file_extension = filename.split('.')[-1]
|
58 |
# Get read mode
|
@@ -61,21 +61,21 @@ def read_from_local(filename: str):
|
|
61 |
else:
|
62 |
mode = 'rb'
|
63 |
# If file is exist, return file
|
64 |
-
if os.path.isfile(os.path.join(
|
65 |
-
with open(os.path.join(
|
66 |
if file_extension == 'json':
|
67 |
return json.load(f)
|
68 |
return f.read()
|
69 |
|
70 |
|
71 |
-
def remove_from_local(filename: str):
|
72 |
# If file is exist, add number to filename
|
73 |
-
if os.path.isfile(os.path.join(
|
74 |
-
os.remove(os.path.join(
|
75 |
|
76 |
|
77 |
-
def remove_from_local_with_expire(filename: str, expire: int):
|
78 |
# Remove file after expire time
|
79 |
if expire is not None and expire > 0:
|
80 |
-
t = Timer(expire, remove_from_local, args=[filename])
|
81 |
t.start()
|
|
|
31 |
return filename
|
32 |
|
33 |
|
34 |
+
def save_to_local(file: bytes | Any, filename: str, is_parse_filename: bool = True, directory: str = TEMP_DIR):
|
35 |
# Parse filename
|
36 |
if is_parse_filename:
|
37 |
filename = parse_filename(filename)
|
|
|
43 |
else:
|
44 |
mode = 'wb'
|
45 |
# Save file
|
46 |
+
with open(os.path.join(directory, filename), mode) as f:
|
47 |
if file_extension == 'json':
|
48 |
json.dump(file, f)
|
49 |
else:
|
|
|
52 |
return f"{APP_DOMAIN}/static/{filename}"
|
53 |
|
54 |
|
55 |
+
def read_from_local(filename: str, directory: str = TEMP_DIR):
|
56 |
# Get type of file
|
57 |
file_extension = filename.split('.')[-1]
|
58 |
# Get read mode
|
|
|
61 |
else:
|
62 |
mode = 'rb'
|
63 |
# If file is exist, return file
|
64 |
+
if os.path.isfile(os.path.join(directory, filename)):
|
65 |
+
with open(os.path.join(directory, filename), mode) as f:
|
66 |
if file_extension == 'json':
|
67 |
return json.load(f)
|
68 |
return f.read()
|
69 |
|
70 |
|
71 |
+
def remove_from_local(filename: str, directory: str = TEMP_DIR):
|
72 |
# If file is exist, add number to filename
|
73 |
+
if os.path.isfile(os.path.join(directory, filename)):
|
74 |
+
os.remove(os.path.join(directory, filename))
|
75 |
|
76 |
|
77 |
+
def remove_from_local_with_expire(filename: str, expire: int, directory: str = TEMP_DIR):
|
78 |
# Remove file after expire time
|
79 |
if expire is not None and expire > 0:
|
80 |
+
t = Timer(expire, remove_from_local, args=[filename, directory])
|
81 |
t.start()
|