fix: add upload images (#50)
Release package / release (push) Successful in 17m59s

Co-authored-by: TakahashiNg <83152264+TakahashiNguyen@users.noreply.github.com>
Reviewed-on: #50
This commit was merged in pull request #50.
This commit is contained in:
2026-05-10 14:10:20 +00:00
parent e963b0f850
commit c6683b28dc
23 changed files with 414 additions and 20 deletions
+32
View File
@@ -0,0 +1,32 @@
# --- Stage 1: Build (Cài đặt thư viện) ---
FROM python:3.9-slim AS builder
WORKDIR /build
# Khởi tạo môi trường ảo để tách biệt thư viện
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY requirements.txt .
RUN pip install --upgrade --no-cache-dir -r requirements.txt
# --- Stage 2: Runtime (Chỉ chạy Prod) ---
FROM python:3.9-slim
WORKDIR /app
# Chỉ copy môi trường ảo đã build xong từ Stage 1
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
# Copy mã nguồn
COPY main.py .
# Tạo folder lưu ảnh và phân quyền (tăng tính bảo mật)
RUN mkdir images && chmod 777 images
# Chạy bằng Uvicorn với chế độ production (tắt reload)
# Port 80 theo yêu cầu trước đó của bạn
EXPOSE 80
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80", "--workers", "4"]
+52
View File
@@ -0,0 +1,52 @@
import uuid
import io
from fastapi import FastAPI, Request, HTTPException
from fastapi.responses import FileResponse
from pathlib import Path
from PIL import Image
import filetype
app = FastAPI()
STORAGE_DIR = Path("images")
STORAGE_DIR.mkdir(exist_ok=True)
@app.post("/")
async def upload_image(request: Request):
body = await request.body()
if not body:
raise HTTPException(status_code=400, detail="Dữ liệu trống")
kind = filetype.guess(body)
if kind is None or not kind.mime.startswith("image/"):
mime_type = kind.mime if kind else "không xác định"
raise HTTPException(
status_code=400, detail=f"Định dạng {mime_type} không được hỗ trợ"
)
try:
img = Image.open(io.BytesIO(body))
random_filename = f"{uuid.uuid4()}.webp"
file_path = STORAGE_DIR / random_filename
img.save(file_path, format="WEBP", quality=80)
return {
"status": "success",
"filename": random_filename,
"original_type": kind.mime,
}
except Exception as e:
raise HTTPException(status_code=500, detail=f"Lỗi xử lý ảnh: {str(e)}")
@app.get("/{name}")
async def get_image(name: str):
file_path = STORAGE_DIR / name
if not file_path.exists():
raise HTTPException(status_code=404, detail="NotFoundImage")
return FileResponse(file_path, media_type="image/webp")
+5
View File
@@ -0,0 +1,5 @@
fastapi
uvicorn
python-multipart
Pillow
filetype