MingDoan commited on
Commit
aabae8d
·
0 Parent(s):

feat: First commit

Browse files
.dockerignore ADDED
@@ -0,0 +1 @@
 
 
1
+ env/
.gitignore ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ env/
2
+ __pycache__/
3
+ .env
4
+ temp/*
5
+
6
+ # Keep the .gitkeep file in the temp/ directory
7
+ !.gitkeep
Dockerfile ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11.7-slim-bookworm
2
+
3
+ WORKDIR /app
4
+
5
+ COPY ./requirements.txt /app
6
+
7
+ RUN pip install -r requirements.txt
8
+
9
+ COPY . /app
10
+
11
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80", "--reload"]
README.md ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div style="width:100%;display:flex;flex-direction:column;justify-content:center;align-items:center">
2
+ <img style="width:80px"
3
+ src="https://seeklogo.com/images/G/google-developers-logo-F8BF3155AC-seeklogo.com.png" alt="logo"/>
4
+ </div>
5
+ <h3 style="text-align:center">Google Developer Student Clubs - FPT University Da Nang</h3>
6
+
7
+ # AI Services
8
+
9
+ ![version](https://img.shields.io/badge/version-0.1.1-green)
10
+ ![release](https://img.shields.io/badge/release-0.1.0-blue)
11
+
12
+ ## ✨ Available Services
13
+
14
+ ## ⏩ Forwarding Server
15
+
16
+ The forwarding server help adding children server for processing. The parent server acts as a controller for load balancing.
17
+
18
+ ```bash
19
+ # Specifying forwarding server by query params `fw`
20
+ curl --location 'https://{api-endpoint}/?fw=0' --request 'POST'
21
+
22
+ # Auto forwarding server. The parent server will controll loading balance among registered servers.
23
+ curl --location 'https://{api-endpoint}/?fw=auto' --request 'POST'
24
+ ```
25
+
26
+ - Get all registered forwarding servers.
27
+
28
+ ```bash
29
+ curl --location 'https://{domain}/service/fw/' --request 'GET'
30
+ ```
31
+
32
+ - Register forwarding server.
33
+
34
+ ```bash
35
+ curl --location 'https://{domain}/service/fw/' --request 'POST' --data '{"url":"{children-base-domain}"}'
36
+ ```
37
+
38
+ - Delete forwarding server.
39
+
40
+ ```bash
41
+ curl --location 'https://{domain}/service/fw/' --request 'DELETE' --data '{"index":0}'
42
+ ```
43
+
44
+ ### Children Server Endpoint Request & Response
45
+
46
+ - `/api/rembg/`
47
+
48
+ ```json
49
+ // Request. Form-data
50
+ {
51
+ "image": "<image-data>"
52
+ }
53
+
54
+ // Response. JSON
55
+ {
56
+ "data": {
57
+ "image": "<static-access-url>"
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## 😊 Contributors
63
+
64
+ - GDSC-FPTU [[gdsc-fptu](https://github.com/gdsc-fptu)]
65
+ - Đoàn Quang Minh [[Ming-doan](https://github.com/Ming-doan)]
apps/apis/__init__.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from .rembg import router as rembg_router
3
+ from .img2text import router as img2text_router
4
+ from .chats import router as chats_router
5
+ from .fd import router as fd_router
6
+
7
+ router = APIRouter(prefix='/api')
8
+
9
+ # Register routes
10
+ router.include_router(rembg_router)
11
+ router.include_router(img2text_router)
12
+ router.include_router(chats_router)
13
+ router.include_router(fd_router)
apps/apis/chats/__init__.py ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from fastapi.responses import JSONResponse
3
+ from fastapi.requests import Request
4
+
5
+ router = APIRouter(prefix='/chats')
6
+ router_base_configs = {
7
+ "tags": ["chats"],
8
+ "response_class": JSONResponse
9
+ }
10
+
11
+
12
+ # Message
13
+ @router.post("/:conversation_id", **router_base_configs)
14
+ def message():
15
+ return {"message": "Hello World"}
16
+
17
+
18
+ # Get conversations
19
+ @router.get("/get", **router_base_configs)
20
+ def get_conversations():
21
+ return {"conversations": "Hello World"}
22
+
23
+
24
+ # Create conversation
25
+ @router.post("/create", **router_base_configs)
26
+ def create_conversation():
27
+ return {"conversation_id": "Hello World"}
28
+
29
+
30
+ # Delete conversation
31
+ @router.delete("/delete", **router_base_configs)
32
+ def delete_conversation():
33
+ return {"conversation": "Hello World"}
apps/apis/fd/__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from fastapi.responses import JSONResponse
3
+
4
+ router = APIRouter(prefix='/fd')
5
+ router_base_configs = {
6
+ "tags": ["fd"],
7
+ "response_class": JSONResponse
8
+ }
9
+
10
+
11
+ # Face detection
12
+ @router.post("/", **router_base_configs)
13
+ def faces_detection():
14
+ return {"faces": "Hello World"}
apps/apis/img2text/__init__.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from fastapi.responses import JSONResponse
3
+
4
+ router = APIRouter(prefix='/img2text')
5
+ router_base_configs = {
6
+ "tags": ["img2text"],
7
+ "response_class": JSONResponse
8
+ }
9
+
10
+
11
+ # Image to text
12
+ @router.post("/", **router_base_configs)
13
+ def image_to_text():
14
+ return {"caption": "Hello World"}
apps/apis/rembg/__init__.py ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter, HTTPException, Depends
2
+ from fastapi.responses import JSONResponse, StreamingResponse
3
+ from apps.services.foward.fw_middleware import forward_middleware, forward_request
4
+ from .models.rembg_model import RembgModel
5
+ from .controllers.rembg_controller import rembg_controller
6
+ from utils.local_storage import save_to_local, remove_from_local_with_expire
7
+
8
+ router = APIRouter(prefix='/rembg')
9
+ router_base_configs = {
10
+ "tags": ["rembg"],
11
+ "response_class": JSONResponse,
12
+ }
13
+
14
+
15
+ # Remove background
16
+ @router.post("/", **router_base_configs)
17
+ async def remove_background(
18
+ image: RembgModel.image = RembgModel.image_default,
19
+ stream: RembgModel.stream = RembgModel.stream_default,
20
+ expire: RembgModel.expire = RembgModel.expire_default,
21
+ fw_index: RembgModel.fw_index = Depends(forward_middleware)
22
+ ):
23
+ # Forward request
24
+ fw_data = {
25
+ "files": {"image": image.file}
26
+ }
27
+ fw_response = forward_request(fw_index, fw_data, '/api/rembg/')
28
+ if fw_response is not None:
29
+ return JSONResponse({
30
+ "message": "Image is processed successfully",
31
+ "access_link": fw_response["data"]['image']
32
+ })
33
+
34
+ # Check if image is None
35
+ if image is None:
36
+ raise HTTPException(status_code=400, detail="Image is required")
37
+ # Check if image is empty
38
+ if image.filename == '':
39
+ raise HTTPException(status_code=400, detail="Image is empty")
40
+ # Read image
41
+ image_bytes = await image.read()
42
+ # Process image
43
+ processed_image = await rembg_controller(image_bytes)
44
+ # If stream is True, return StreamingResponse
45
+ if RembgModel.stream_parser(stream):
46
+ return StreamingResponse(processed_image, media_type="application/octet-stream", headers={"Content-Disposition": f"attachment;filename={image.filename}"})
47
+ # If stream is False, save locally and return access link
48
+ else:
49
+ # Save image
50
+ local_path = save_to_local(processed_image.read(), image.filename)
51
+ # Automatic delete file
52
+ remove_from_local_with_expire(local_path, expire)
53
+ # Return access link
54
+ return JSONResponse({
55
+ "message": "Image is processed successfully",
56
+ "access_link": local_path
57
+ })
apps/apis/rembg/controllers/rembg_controller.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import rembg
2
+ import io
3
+
4
+
5
+ async def rembg_controller(image: bytes):
6
+ # Remove background
7
+ image = rembg.remove(image)
8
+ # Return image
9
+ return io.BytesIO(image)
apps/apis/rembg/models/rembg_model.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import UploadFile, File, Form
2
+
3
+
4
+ class RembgModel:
5
+ image = UploadFile | None
6
+ image_default = File(
7
+ None, description="Image to remove background", example="image.jpg")
8
+ stream = str | None
9
+ stream_default = Form(
10
+ None, description="Is return a streaming or access json", example="false")
11
+ expire = int | None
12
+ expire_default = Form(
13
+ None, description="Expire time of access link", example=3600)
14
+ fw_index = int | None
15
+ fw_index_default = Form(
16
+ None, description="Forward destination index", example=0)
17
+
18
+ def stream_parser(x): return False if x == 'false' or x == 0 else True
apps/create_app.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from fastapi.staticfiles import StaticFiles
3
+ from fastapi.middleware.cors import CORSMiddleware
4
+ from utils.metadata import DOC_SWAGGER
5
+
6
+
7
+ def create_app():
8
+ app = FastAPI(**DOC_SWAGGER)
9
+ app.add_middleware(
10
+ CORSMiddleware,
11
+ allow_origins=['*'],
12
+ allow_credentials=True,
13
+ allow_methods=['*'],
14
+ allow_headers=['*'],
15
+ )
16
+ app.mount("/static", StaticFiles(directory="temp"), name="static")
17
+ return app
apps/services/__init__.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from .foward import router as foward_router
3
+
4
+ router = APIRouter(prefix='/service')
5
+
6
+ # Register routes
7
+ router.include_router(foward_router)
apps/services/foward/__init__.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from fastapi.responses import JSONResponse
3
+ from .models.fw_model import CreateFwDestinationModel, DeleteFwDestinationModel
4
+ from .fw_storage import get_fw_destinations, append_fw_destination, delete_fw_destination
5
+
6
+
7
+ router = APIRouter(prefix='/fw')
8
+ router_base_configs = {
9
+ "tags": ["fw"],
10
+ "response_class": JSONResponse
11
+ }
12
+
13
+
14
+ # Create foward destination
15
+ @router.post("/", **router_base_configs)
16
+ def create_forward_destination(data: CreateFwDestinationModel):
17
+ index = append_fw_destination(data.url)
18
+ return {"fw_index": index}
19
+
20
+
21
+ # Delete foward destination
22
+ @router.delete("/", **router_base_configs)
23
+ def delete_forward_destination(data: DeleteFwDestinationModel):
24
+ delete_fw_destination(data.index)
25
+ return {"fw_index": data.index}
26
+
27
+
28
+ # Get foward destinations
29
+ @router.get("/", **router_base_configs)
30
+ def get_forward_destinations():
31
+ return {"fw": get_fw_destinations()}
apps/services/foward/fw_middleware.py ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any, Literal
2
+ import requests
3
+ from fastapi import HTTPException
4
+ from .fw_storage import get_fw_destinations, update_fw_destination
5
+
6
+
7
+ async def verify_fw_resources(url: str) -> bool:
8
+ try:
9
+ response = requests.get(url + '/health')
10
+ if response.status_code == 200:
11
+ return True
12
+ else:
13
+ return False
14
+ except Exception:
15
+ return False
16
+
17
+
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(
25
+ status_code=400, detail="Invalid forward destination")
26
+
27
+ # If forward destination is auto, get the destination with the least tasks
28
+ fw_destinations = get_fw_destinations()
29
+ if fw == 'auto':
30
+ if len(fw_destinations) != 0:
31
+ # Sort resources by tasks
32
+ fw_destinations.sort(key=lambda x: x['tasks'])
33
+ # Verify forward destination resources
34
+ fw = 0
35
+ for i in range(0, len(fw_destinations)):
36
+ is_resource_available = await verify_fw_resources(fw_destinations[fw]['url'])
37
+ if is_resource_available:
38
+ fw = i
39
+ break
40
+ else:
41
+ fw = None
42
+ # Update forward destination tasks
43
+ if fw is not None:
44
+ update_fw_destination(fw, fw_destinations[fw]['tasks'] + 1)
45
+ else:
46
+ fw = None
47
+ # If forward destination is not auto, update forward destination tasks
48
+ else:
49
+ update_fw_destination(fw, fw_destinations[fw]['tasks'] + 1)
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
58
+ # Call request
59
+ try:
60
+ if method == 'GET':
61
+ response = requests.get(fw_url)
62
+ elif method == 'POST':
63
+ response = requests.post(fw_url, **data)
64
+ elif method == 'PUT':
65
+ response = requests.put(fw_url, **data)
66
+ elif method == 'DELETE':
67
+ response = requests.delete(fw_url, **data)
68
+ else:
69
+ raise HTTPException(
70
+ status_code=400, detail="Invalid request method on forwarding request")
71
+ except Exception as e:
72
+ print("Forwarding Error: ", e)
73
+ response = None
74
+ # Update forward destination tasks
75
+ update_fw_destination(fw_index, fw_destinations[fw_index]['tasks'] - 1)
76
+ # Return response
77
+ return response.json() if response is not None else None
apps/services/foward/fw_storage.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
12
+
13
+
14
+ def append_fw_destination(url: str):
15
+ # Remove the last / if exist
16
+ if url[-1] == '/':
17
+ url = url[:-1]
18
+ # Get forward destinations
19
+ forward_destinations = get_fw_destinations()
20
+ # Append new destination
21
+ forward_destinations.append({
22
+ "tasks": 0,
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
+
30
+
31
+ def update_fw_destination(index: int, tasks: int):
32
+ # Get forward destinations
33
+ forward_destinations = get_fw_destinations()
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):
41
+ # Get forward destinations
42
+ forward_destinations = get_fw_destinations()
43
+ # Delete destination
44
+ del forward_destinations[index]
45
+ # Save to local
46
+ save_to_local(forward_destinations, FOWARD_JSON_FILE, False)
apps/services/foward/models/fw_model.py ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel
2
+
3
+
4
+ class CreateFwDestinationModel(BaseModel):
5
+ url: str = None
6
+
7
+
8
+ class DeleteFwDestinationModel(BaseModel):
9
+ index: int = None
docker-compose.yaml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: '3.8'
2
+
3
+ services:
4
+ api:
5
+ build: .
6
+ container_name: "gdsc-ai-service-container"
7
+ ports:
8
+ - "8000:80"
9
+ volumes:
10
+ - .:/app
11
+ - /app/env
12
+ env_file:
13
+ - .env
main.py ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Google Developer Student Clubs - FPT University Da Nang
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
9
+
10
+ app = create_app()
11
+
12
+ # Register apps routes
13
+ app.include_router(api_router)
14
+ app.include_router(service_router)
15
+
16
+ # Config uvicorn
17
+ if os.environ.get("ENV", "production") == 'development':
18
+ uvicorn.run(app, port=8000)
requirements.txt ADDED
Binary file (2.18 kB). View file
 
temp/.gitkeep ADDED
File without changes
utils/constants.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+
3
+ 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>
10
+ <head>
11
+ <meta charset="utf-8">
12
+ <meta name="viewport" content="width=device-width, initial-scale=1">
13
+ <title>GDSC AI Service</title>
14
+ </head>
15
+ <body>
16
+ <img src="https://seeklogo.com/images/G/google-developers-logo-F8BF3155AC-seeklogo.com.png" alt="logo" width="100">
17
+ <h1>GDSC AI Back-end Service</h1>
18
+ <span>Served URL: </span>
19
+ <a href="{APP_DOMAIN}">{APP_DOMAIN}</a>
20
+ <ul>
21
+ <li>Remove Background Service [POST]</li>
22
+ <code>{APP_DOMAIN}/api/rembg</code>
23
+ </ul>
24
+ <ul>
25
+ <li>Image to Text [POST]</li>
26
+ <code>{APP_DOMAIN}/api/img2text</code>
27
+ </ul>
28
+ <ul>
29
+ <li>Chats [POST]</li>
30
+ <code>{APP_DOMAIN}/api/chats</code>
31
+ </ul>
32
+ <ul>
33
+ <li>Face Detection [POST]</li>
34
+ <code>{APP_DOMAIN}/api/fd</code>
35
+ </ul>
36
+ </body>
37
+ </html>
38
+ '''
utils/local_storage.py ADDED
@@ -0,0 +1,81 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Any
2
+ import os
3
+ import json
4
+ from threading import Timer
5
+ from .constants import TEMP_DIR, APP_DOMAIN
6
+
7
+
8
+ def parse_filename(filename: str):
9
+ filename = filename.replace(' ', '_')
10
+ filename = filename.replace('(', '')
11
+ filename = filename.replace(')', '')
12
+ filename = filename.replace('[', '')
13
+ filename = filename.replace(']', '')
14
+ filename = filename.replace('{', '')
15
+ filename = filename.replace('}', '')
16
+ filename = filename.replace('<', '')
17
+ filename = filename.replace('>', '')
18
+ filename = filename.replace(';', '')
19
+ filename = filename.replace(':', '')
20
+ filename = filename.replace('"', '')
21
+ filename = filename.replace("'", '')
22
+ filename = filename.replace('\\', '')
23
+ filename = filename.replace('/', '')
24
+ filename = filename.replace('|', '')
25
+ filename = filename.replace('?', '')
26
+ filename = filename.replace('*', '')
27
+ # If file is exist, add number to filename
28
+ if os.path.isfile(os.path.join(TEMP_DIR, filename)):
29
+ filename = filename.split('.')
30
+ filename = f"{filename[0]}_1.{filename[1]}"
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)
38
+ # Get type of file
39
+ file_extension = filename.split('.')[-1]
40
+ # Get write mode
41
+ if file_extension == 'json':
42
+ mode = 'w'
43
+ else:
44
+ mode = 'wb'
45
+ # Save file
46
+ with open(os.path.join(TEMP_DIR, filename), mode) as f:
47
+ if file_extension == 'json':
48
+ json.dump(file, f)
49
+ else:
50
+ f.write(file)
51
+ # Return access link
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
59
+ if file_extension == 'json':
60
+ mode = 'r'
61
+ else:
62
+ mode = 'rb'
63
+ # If file is exist, return file
64
+ if os.path.isfile(os.path.join(TEMP_DIR, filename)):
65
+ with open(os.path.join(TEMP_DIR, 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):
72
+ # If file is exist, add number to filename
73
+ if os.path.isfile(os.path.join(TEMP_DIR, filename)):
74
+ os.remove(os.path.join(TEMP_DIR, filename))
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()
utils/metadata.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ DOC_SWAGGER = {
2
+ "title": "GDSC AI Service",
3
+ "description": "GDSC AI Back-end Service",
4
+ "version": "0.0.1",
5
+ "openapi": "3.0.2",
6
+ "info": {
7
+ "title": "GDSC AI Service",
8
+ "description": "GDSC AI Back-end Service",
9
+ "version": "0.0.1"
10
+ },
11
+ "docs_url": "/",
12
+ "openapi_tags": [
13
+ {
14
+ "name": "rembg",
15
+ "description": "Remove background from image"
16
+ },
17
+ {
18
+ "name": "img2text",
19
+ "description": "Extract text from image"
20
+ },
21
+ {
22
+ "name": "chats",
23
+ "description": "Chat with AI"
24
+ },
25
+ {
26
+ "name": "fd",
27
+ "description": "Detect faces from image"
28
+ },
29
+ {
30
+ "name": "fw",
31
+ "description": "Foward request to other services"
32
+ }
33
+ ]
34
+ }