Skip to content

Commit

Permalink
Refactor backend of server-api
Browse files Browse the repository at this point in the history
  • Loading branch information
yihong1120 committed Dec 17, 2024
1 parent a4e600e commit e8711fb
Show file tree
Hide file tree
Showing 24 changed files with 260 additions and 242 deletions.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pip install -r requirements.txt
### 3. 啟動伺服器
使用以下指令啟動伺服器:
```sh
uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000
uvicorn examples.YOLO_server_api.backend.app:sio_app --host 127.0.0.1 --port 8000
```

### 4. 發送請求
Expand All @@ -58,7 +58,7 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000

### YOLO 伺服器 API

- **`POST /detect`**:對上傳的影像執行物件檢測。
- **`POST /api/detect`**:對上傳的影像執行物件檢測。
- **參數**
- `file`(影像):要檢測的影像檔案。
- `model`(字串):使用的 YOLO 模型(預設:`yolo11n`)。
Expand All @@ -71,7 +71,7 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000

### 使用者管理 API

- **`POST /add_user`**:新增使用者。
- **`POST /api/add_user`**:新增使用者。
- **參數**
- `username`(字串):使用者名稱。
- `password`(字串):密碼。
Expand All @@ -83,15 +83,15 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000
http://localhost:8000/add_user
```

- **`DELETE /delete_user/<username>`**:刪除使用者。
- **`DELETE /api/delete_user/<username>`**:刪除使用者。
- **參數**
- `username`(字串):要刪除的使用者名稱。
- **範例**
```sh
curl -X DELETE http://localhost:8000/delete_user/admin
```

- **`PUT /update_username`**:更新使用者名稱。
- **`PUT /api/update_username`**:更新使用者名稱。
- **參數**
- `old_username`(字串):現有使用者名稱。
- `new_username`(字串):新使用者名稱。
Expand All @@ -102,7 +102,7 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000
http://localhost:8000/update_username
```

- **`PUT /update_password`**:更新使用者密碼。
- **`PUT /api/update_password`**:更新使用者密碼。
- **參數**
- `username`(字串):使用者名稱。
- `new_password`(字串):新密碼。
Expand All @@ -113,7 +113,7 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000
http://localhost:8000/update_password
```

- **`PUT /set_user_active_status`**:設置使用者啟用狀態。
- **`PUT /api/set_user_active_status`**:設置使用者啟用狀態。
- **參數**
- `username`(字串):使用者名稱。
- `is_active`(布林值):啟用狀態(`true``false`)。
Expand All @@ -128,7 +128,7 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000

### 模型管理 API

- **`POST /model_file_update`**:更新 YOLO 模型檔案。
- **`POST /api/model_file_update`**:更新 YOLO 模型檔案。
- **參數**
- `model`(字串):模型名稱。
- `file`(檔案):模型檔案。
Expand All @@ -137,7 +137,7 @@ uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000
curl -X POST -F "model=yolo11n" -F "file=@path/to/model.pt" http://localhost:8000/model_file_update
```

- **`POST /get_new_model`**:檢索最新的 YOLO 模型檔案。
- **`POST /api/get_new_model`**:檢索最新的 YOLO 模型檔案。
- **參數**
- `model`(字串):模型名稱。
- `last_update_time`(ISO 8601 字串):上次更新時間。
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Update the configuration in `config.py` or `.env`:
### 3. Run the Server
You can start the server with:
```sh
uvicorn examples.YOLO_server_api.app:sio_app --host 127.0.0.1 --port 8000
uvicorn examples.YOLO_server_api.backend.app:sio_app --host 127.0.0.1 --port 8000
```

### 4. Send Requests
Expand All @@ -58,7 +58,7 @@ Use tools like `curl`, Postman, or your browser to interact with the API.

### YOLO Server API Endpoints

- **`POST /detect`**: Perform object detection on an uploaded image.
- **`POST /api/detect`**: Perform object detection on an uploaded image.
- **Parameters**:
- `file` (image): The image file for detection.
- `model` (str): The YOLO model to use (default: `yolo11n`).
Expand All @@ -71,7 +71,7 @@ Use tools like `curl`, Postman, or your browser to interact with the API.

### User Management Endpoints

- **`POST /add_user`**: Add a new user.
- **`POST /api/add_user`**: Add a new user.
- **Parameters**:
- `username` (str): The username.
- `password` (str): The password.
Expand All @@ -83,15 +83,15 @@ Use tools like `curl`, Postman, or your browser to interact with the API.
http://localhost:8000/add_user
```

- **`DELETE /delete_user/<username>`**: Delete a user.
- **`DELETE /api/delete_user/<username>`**: Delete a user.
- **Parameters**:
- `username` (str): The username to delete.
- **Example**:
```sh
curl -X DELETE http://localhost:8000/delete_user/admin
```

- **`PUT /update_username`**: Update a user's username.
- **`PUT /api/update_username`**: Update a user's username.
- **Parameters**:
- `old_username` (str): Existing username.
- `new_username` (str): New username.
Expand All @@ -102,7 +102,7 @@ Use tools like `curl`, Postman, or your browser to interact with the API.
http://localhost:8000/update_username
```
- **`PUT /update_password`**: Update a user's password.
- **`PUT /api/update_password`**: Update a user's password.
- **Parameters**:
- `username` (str): The username.
- `new_password` (str): The new password.
Expand All @@ -113,7 +113,7 @@ Use tools like `curl`, Postman, or your browser to interact with the API.
http://localhost:8000/update_password
```

- **`PUT /set_user_active_status`**: Set a user's active status.
- **`PUT /api/set_user_active_status`**: Set a user's active status.
- **Parameters**:
- `username` (str): The username.
- `is_active` (bool): Active status (`true` or `false`).
Expand All @@ -128,7 +128,7 @@ Use tools like `curl`, Postman, or your browser to interact with the API.
### Models Management Endpoints
- **`POST /model_file_update`**: Update a YOLO model file.
- **`POST /api/model_file_update`**: Update a YOLO model file.
- **Parameters**:
- `model` (str): Model name.
- `file` (file): Model file to upload.
Expand All @@ -137,7 +137,7 @@ Use tools like `curl`, Postman, or your browser to interact with the API.
curl -X POST -F "model=yolo11n" -F "file=@path/to/model.pt" http://localhost:8000/model_file_update
```
- **`POST /get_new_model`**: Retrieve an updated YOLO model file if available.
- **`POST /api/get_new_model`**: Retrieve an updated YOLO model file if available.
- **Parameters**:
- `model` (str): Model name.
- `last_update_time` (ISO 8601 string): Last update time.
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class UserLogin(BaseModel):
password: str


@auth_router.post('/token')
@auth_router.post('/api/token')
async def create_token(user: UserLogin, db: AsyncSession = Depends(get_db)):
"""
Authenticates a user and generates an access token for them.
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -117,15 +117,15 @@ async def remove_overlapping_labels(
category_indices['hardhat'],
category_indices['no_hardhat'],
datas,
0.8,
0.5,
),
)
to_remove.update(
await find_overlaps(
category_indices['safety_vest'],
category_indices['no_safety_vest'],
datas,
0.8,
0.5,
),
)

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@

from sahi.predict import AutoDetectionModel
from sqlalchemy import Boolean
from sqlalchemy import Column
from sqlalchemy import DateTime
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy.ext.asyncio import async_sessionmaker
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.ext.asyncio import create_async_engine
from sqlalchemy.orm import declarative_base
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from watchdog.events import FileSystemEventHandler
from watchdog.observers import Observer
from werkzeug.security import check_password_hash
Expand All @@ -36,7 +37,10 @@
)

# Base for SQLAlchemy ORM models
Base = declarative_base()


class Base(DeclarativeBase):
pass


async def get_db() -> AsyncGenerator[AsyncSession]:
Expand All @@ -50,60 +54,42 @@ async def get_db() -> AsyncGenerator[AsyncSession]:

class User(Base):
"""
Represents a user entity in the database with password hashing for
security.
Represents a user entity in the database
with password hashing for security.
"""

__tablename__ = 'users'
id = Column(Integer, primary_key=True, index=True)
username = Column(String(80), unique=True, nullable=False)
password_hash = Column(String(255), nullable=False)
# admim, model_manage, user, guest
role = Column(String(20), default='user', nullable=False)
is_active = Column(Boolean, default=True, nullable=False)
created_at = Column(
DateTime, default=datetime.now(
timezone.utc,
), nullable=False,

id: Mapped[int] = mapped_column(Integer, primary_key=True, index=True)
username: Mapped[str] = mapped_column(
String(80), unique=True, nullable=False,
)
password_hash: Mapped[str] = mapped_column(String(255), nullable=False)
role: Mapped[str] = mapped_column(
String(20), default='user', nullable=False,
)
is_active: Mapped[bool] = mapped_column(
Boolean, default=True, nullable=False,
)
updated_at = Column(
DateTime, default=datetime.now(
timezone.utc,
), onupdate=datetime.now(timezone.utc), nullable=False,
created_at: Mapped[datetime] = mapped_column(
DateTime, default=datetime.now(timezone.utc), nullable=False,
)
updated_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now(timezone.utc),
onupdate=datetime.now(timezone.utc),
nullable=False,
)

def set_password(self, password: str) -> None:
"""
Hashes the given password and stores it as the password hash.
Args:
password (str): The plaintext password to be hashed.
"""
self.password_hash = generate_password_hash(password)

async def check_password(self, password: str) -> bool:
"""
Checks if the provided password matches the stored hashed password.
Args:
password (str): The plaintext password to verify.
Returns:
bool: True if the password is correct, False otherwise.
"""
return await asyncio.to_thread(
check_password_hash,
str(self.password_hash),
password,
check_password_hash, str(self.password_hash), password,
)

def to_dict(self):
"""
Returns the user entity as a dictionary.
Returns:
dict: The user entity as a dictionary.
"""
return {
'id': self.id,
'username': self.username,
Expand Down Expand Up @@ -200,7 +186,7 @@ def load_single_model(self, model_name: str) -> AutoDetectionModel:
AutoDetectionModel: The loaded model ready for predictions.
"""
return AutoDetectionModel.from_pretrained(
'yolov8',
'yolo11',
model_path=str(self.base_model_path / f"best_{model_name}.pt"),
device='cuda:0',
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ class DetectionRequest(BaseModel):
model: str


@detection_router.post('/detect')
@detection_router.post('/api/detect')
async def detect(
image: UploadFile = File(...),
model: str = 'yolo11n',
Expand Down Expand Up @@ -106,7 +106,7 @@ class UserCreate(BaseModel):
role: str = 'user'


@user_management_router.post('/add_user')
@user_management_router.post('/api/add_user')
async def add_user_route(
user: UserCreate,
db: AsyncSession = Depends(get_db),
Expand Down Expand Up @@ -153,7 +153,7 @@ class DeleteUser(BaseModel):
username: str


@user_management_router.post('/delete_user')
@user_management_router.post('/api/delete_user')
async def delete_user_route(
user: DeleteUser,
db: AsyncSession = Depends(get_db),
Expand Down Expand Up @@ -200,7 +200,7 @@ class UpdateUsername(BaseModel):
new_username: str


@user_management_router.put('/update_username')
@user_management_router.put('/api/update_username')
async def update_username_route(
update_data: UpdateUsername,
db: AsyncSession = Depends(get_db),
Expand Down Expand Up @@ -251,7 +251,7 @@ class UpdatePassword(BaseModel):
role: str = 'user'


@user_management_router.put('/update_password')
@user_management_router.put('/api/update_password')
async def update_password_route(
update_data: UpdatePassword,
db: AsyncSession = Depends(get_db),
Expand Down Expand Up @@ -304,7 +304,7 @@ class SetUserActiveStatus(BaseModel):
is_active: bool


@user_management_router.put('/set_user_active_status')
@user_management_router.put('/api/set_user_active_status')
async def set_user_active_status_route(
user_status: SetUserActiveStatus, # 使用請求正文接收數據
db: AsyncSession = Depends(get_db),
Expand Down Expand Up @@ -376,7 +376,7 @@ def as_form(
return cls(model=model, file=file)


@model_management_router.post('/model_file_update')
@model_management_router.post('/api/model_file_update')
async def model_file_update(
data: ModelFileUpdate = Depends(ModelFileUpdate.as_form),
credentials: JwtAuthorizationCredentials = Depends(jwt_access),
Expand All @@ -403,7 +403,8 @@ async def model_file_update(

try:
# Ensure the filename is secure
secure_file_name = secure_filename(data.file.filename)
filename = data.file.filename or 'default_model_name'
secure_file_name = secure_filename(filename)
temp_dir = Path('/tmp')
temp_path = temp_dir / secure_file_name

Expand Down Expand Up @@ -446,7 +447,7 @@ class UpdateModelRequest(BaseModel):
last_update_time: str


@model_management_router.post('/get_new_model')
@model_management_router.post('/api/get_new_model')
async def get_new_model(
update_request: UpdateModelRequest = Body(...),
) -> dict:
Expand Down
File renamed without changes.
Loading

0 comments on commit e8711fb

Please sign in to comment.