Skip to content

Commit ddca844

Browse files
committed
feat: enhance configuration loading and add image processing endpoints
1 parent 0f1e5e5 commit ddca844

File tree

3 files changed

+83
-8
lines changed

3 files changed

+83
-8
lines changed

src/common/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ def from_env(cls) -> "AppConfig":
3131
)
3232

3333

34+
print("AppConfig loaded from environment variables:", AppConfig.from_env())
35+
36+
3437
def load_json_config(path: Path) -> dict[str, Any]:
3538
"""Load configuration from JSON file.
3639

src/modules/api/app.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
"""FastAPI application factory."""
22

3+
from typing import List
34
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
45
from fastapi.middleware.cors import CORSMiddleware
6+
from fastapi.staticfiles import StaticFiles
7+
from fastapi.templating import Jinja2Templates
8+
from fastapi.responses import HTMLResponse
9+
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request
510

611
from .routes import v1_router
712

@@ -21,6 +26,7 @@ async def broadcast(self, message: str):
2126
await connection.send_text(message)
2227

2328
manager = ConnectionManager()
29+
templates = Jinja2Templates(directory="templates")
2430

2531
def create_app() -> FastAPI:
2632
"""Create and configure the FastAPI application."""
@@ -35,6 +41,8 @@ def create_app() -> FastAPI:
3541
allow_headers=["*"],
3642
)
3743

44+
app.mount("/static", StaticFiles(directory="static"), name="static")
45+
3846
# Include routers
3947
app.include_router(v1_router)
4048

@@ -60,6 +68,11 @@ async def websocket_endpoint(websocket: WebSocket):
6068
manager.disconnect(websocket)
6169
await manager.broadcast("A client disconnected")
6270

71+
72+
@app.get("/room/{room_name}", response_class=HTMLResponse)
73+
async def broadcaster(request: Request, room_name: str):
74+
return templates.TemplateResponse("broadcaster.html", {"request": request, "room_name": room_name})
75+
6376
return app
6477

6578

src/modules/api/routes/v1.py

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,29 @@
11
"""API v1 route handlers."""
22

3-
from fastapi import APIRouter, Response
3+
from fastapi import APIRouter, Response, File, UploadFile
4+
import numpy as np
5+
from fastapi.responses import StreamingResponse
46
from typing import Dict, List
5-
from src.modules.transporter import publish_message
7+
from src.modules.transporter import add_to_queue
68
from src.modules.models.index import embed_text
79
import io
810
# Create v1 router
911
router = APIRouter(prefix='/v1', tags=['v1'])
1012
import matplotlib.pyplot as plt
13+
from src.modules.transporter.redis_client import pubsub
14+
from src.modules.transporter.kafka import kafka_pubsub
1115

1216
@router.get("/hello")
1317
async def hello_world():
1418
"""Hello world endpoint."""
15-
publish_message("hello-python", "Hello from FastAPI!")
16-
embed = embed_text("Hello, world!")
17-
print(f"Generated embedding: {embed}")
18-
return {"message": "Hello, reloaded!", "embedding": list(embed)}
19+
add_to_queue("hello-python", "Hello from FastAPI!")
20+
await pubsub.publish('chat', "message")
21+
await kafka_pubsub.publish('chat', "messagejbdjchsjdhcjsdchbsjdch")
22+
return {"message": "Hello, reloaded!"}
1923

2024
@router.get("/health")
21-
async def health_check() -> Dict[str, str]:
25+
async def health_check(msg) -> Dict[str, str]:
26+
print("[chat rehealthdis] Received: message")
2227
"""Health check endpoint."""
2328
return {"status": "healthy"}
2429

@@ -49,4 +54,58 @@ async def get_plot():
4954
buf.seek(0)
5055

5156
# Trả về dưới dạng ảnh PNG
52-
return Response(content=buf.getvalue(), media_type="image/png")
57+
return Response(content=buf.getvalue(), media_type="image/png")
58+
59+
import cv2
60+
@router.post("/edit-image/")
61+
async def edit_image(file: UploadFile = File(...)):
62+
import cv2
63+
# Đọc file ảnh từ request
64+
contents = await file.read()
65+
nparr = np.frombuffer(contents, np.uint8)
66+
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
67+
68+
# Xử lý ảnh: ví dụ chuyển sang ảnh xám
69+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
70+
71+
# Chuyển lại thành ảnh màu để trả về (nếu cần)
72+
result = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)
73+
74+
# Encode ảnh thành bytes
75+
_, img_encoded = cv2.imencode('.jpg', result)
76+
return StreamingResponse(io.BytesIO(img_encoded.tobytes()), media_type="image/jpeg")
77+
78+
79+
# Load bộ phân loại khuôn mặt Haar Cascade
80+
face_cascade = cv2.CascadeClassifier(
81+
cv2.data.haarcascades + "haarcascade_frontalface_default.xml"
82+
)
83+
84+
@router.post("/detect-faces/")
85+
async def detect_faces(file: UploadFile = File(...)):
86+
# Đọc dữ liệu ảnh
87+
contents = await file.read()
88+
nparr = np.frombuffer(contents, np.uint8)
89+
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
90+
91+
# Chuyển sang ảnh xám để nhận diện
92+
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
93+
94+
# Phát hiện khuôn mặt
95+
faces = face_cascade.detectMultiScale(
96+
gray,
97+
scaleFactor=1.1,
98+
minNeighbors=5,
99+
minSize=(30, 30)
100+
)
101+
102+
# Vẽ hình chữ nhật quanh khuôn mặt
103+
for (x, y, w, h) in faces:
104+
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2)
105+
106+
# Chuyển ảnh kết quả thành bytes
107+
_, img_encoded = cv2.imencode('.jpg', img)
108+
return StreamingResponse(
109+
io.BytesIO(img_encoded.tobytes()),
110+
media_type="image/jpeg"
111+
)

0 commit comments

Comments
 (0)