Compare commits
1 Commits
master
...
zelda.upda
| Author | SHA1 | Date |
|---|---|---|
|
|
5154464646 |
|
|
@ -1,5 +1,7 @@
|
|||
Run client: npm run dev or npm run build && npm run preview
|
||||
|
||||
==> Build client xong => coppy file asset và index vào folder static của server => thêm prefix static vào link của assets trong file index VD: /static/assets
|
||||
==> Build client xong => coppy file asset và index vào folder static của server => thêm prefix static vào link của assets trong file index VD: /camera/static/assets
|
||||
|
||||
Run server uvicorn main:app --reload
|
||||
|
||||
nohup uvicorn main:app --host 172.16.6.38 --port 8080 > log.log 2>&1 &
|
||||
|
|
|
|||
|
|
@ -6,45 +6,76 @@ from fastapi import UploadFile
|
|||
|
||||
URL_API = "https://ms.prology.net/api/v1"
|
||||
|
||||
def send_image(id, file: UploadFile, student_name: str, status: str):
|
||||
# def send_image(id, file: UploadFile, student_name: str, status: str):
|
||||
# id = str(id)
|
||||
|
||||
# # Tạo folder theo ngày
|
||||
# today = datetime.datetime.now().strftime("%Y_%m_%d")
|
||||
# folder_path = f"./images/{today}"
|
||||
|
||||
# if not os.path.exists(folder_path):
|
||||
# os.makedirs(folder_path)
|
||||
|
||||
# # Tạo file name chuẩn
|
||||
# file_name = (
|
||||
# f"{student_name}_"
|
||||
# f"{status}_at_{datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}.png"
|
||||
# )
|
||||
|
||||
# file_path = os.path.join(folder_path, file_name)
|
||||
|
||||
# # Lưu file UploadFile xuống
|
||||
# with open(file_path, "wb") as f:
|
||||
# f.write(file.file.read())
|
||||
|
||||
# # Mở lại file để gửi API
|
||||
# with open(file_path, "rb") as image_file:
|
||||
# files = {"image": image_file}
|
||||
# data = {"id": id, "file_name": file_name}
|
||||
|
||||
# try:
|
||||
# response = requests.post(
|
||||
# URL_API + "/admin/tracking/send-image",
|
||||
# data=data,
|
||||
# files=files
|
||||
# )
|
||||
# response.raise_for_status()
|
||||
# res = response.json()
|
||||
# except Exception as e:
|
||||
# return {"status": False, "message": str(e)}
|
||||
|
||||
# return res
|
||||
|
||||
|
||||
def send_image(id, image_bytes, student_name: str, status: str):
|
||||
id = str(id)
|
||||
|
||||
# Tạo folder theo ngày
|
||||
today = datetime.datetime.now().strftime("%Y_%m_%d")
|
||||
folder_path = f"./images/{today}"
|
||||
os.makedirs(folder_path, exist_ok=True)
|
||||
|
||||
if not os.path.exists(folder_path):
|
||||
os.makedirs(folder_path)
|
||||
|
||||
# Tạo file name chuẩn
|
||||
file_name = (
|
||||
f"{student_name}_"
|
||||
f"{status}_at_{datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S')}.png"
|
||||
)
|
||||
safe_student = "".join(c for c in student_name if c.isalnum() or c in ("-", "_"))
|
||||
safe_status = "".join(c for c in status if c.isalnum() or c in ("-", "_"))
|
||||
timestamp = datetime.datetime.now().strftime("%Y_%m_%d_%H_%M_%S")
|
||||
|
||||
file_name = f"{safe_student}_{safe_status}_at_{timestamp}.png"
|
||||
file_path = os.path.join(folder_path, file_name)
|
||||
|
||||
# Lưu file UploadFile xuống
|
||||
# Lưu xuống
|
||||
with open(file_path, "wb") as f:
|
||||
f.write(file.file.read())
|
||||
|
||||
# Mở lại file để gửi API
|
||||
with open(file_path, "rb") as image_file:
|
||||
files = {"image": image_file}
|
||||
data = {"id": id, "file_name": file_name}
|
||||
f.write(image_bytes)
|
||||
|
||||
# Gửi API
|
||||
try:
|
||||
with open(file_path, "rb") as image_file:
|
||||
response = requests.post(
|
||||
URL_API + "/admin/tracking/send-image",
|
||||
data=data,
|
||||
files=files
|
||||
data={"id": id, "file_name": file_name},
|
||||
files={"image": image_file}
|
||||
)
|
||||
response.raise_for_status()
|
||||
res = response.json()
|
||||
except Exception as e:
|
||||
return {"status": False, "message": str(e)}
|
||||
|
||||
return res
|
||||
print("Send image failed:", e)
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
VITE_API_BASE_URL = "/"
|
||||
VITE_API_BASE_URL = "/camera"
|
||||
# VITE_API_BASE_URL = "http://127.0.0.1:8000"
|
||||
VITE_API_BASE_MS = "https://ms.prology.net"
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ class MsApi {
|
|||
Authorization:
|
||||
"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL21zLnByb2xvZ3kubmV0L2FwaS92MS9hZG1pbi9sb2dpbiIsImlhdCI6MTc1Njg2MDQ1OSwiZXhwIjoxNzg4Mzk2NDU5LCJuYmYiOjE3NTY4NjA0NTksImp0aSI6IkRrb0NLbHBKV1pkNnZCN0QiLCJzdWIiOiIxNSIsInBydiI6ImQyZmYyOTMzOWE4YTNlODJjMzU4MmE1YThlNzM5ZGYxNzg5YmIxMmYifQ.DoHqHeAGGxpvzlNQ9dAZjZf2Yl573XCgNBT8ZiSx5N4",
|
||||
},
|
||||
baseURL: "https://ms.prology.net/api/v1/admin",
|
||||
baseURL: import.meta.env.VITE_API_BASE_MS + "/api/v1/admin",
|
||||
method: "GET",
|
||||
url: "timekeeping",
|
||||
params: {
|
||||
|
|
|
|||
|
|
@ -114,10 +114,13 @@ export default function TabFeatures() {
|
|||
} catch (error) {
|
||||
const data = error as AxiosError;
|
||||
|
||||
toast.error(
|
||||
const message =
|
||||
(data.response?.data as any)?.message ||
|
||||
"Error In Checking: " + JSON.stringify(data)
|
||||
);
|
||||
"Error In Checking: " + JSON.stringify(data);
|
||||
|
||||
if ((message as string).includes("No face detected")) return;
|
||||
|
||||
toast.error(message);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
|
|
@ -135,7 +138,7 @@ export default function TabFeatures() {
|
|||
// ← cách đúng nhất để detect phím cách
|
||||
e.preventDefault(); // nếu không muốn scroll
|
||||
|
||||
if (!loading) return;
|
||||
if (loading) return;
|
||||
|
||||
captureAndCheck();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ import TabFeatures from "./components/tab-features";
|
|||
|
||||
export default function Main() {
|
||||
const [isSidebarOpen, setIsSidebarOpen] = useState(true);
|
||||
const [isLeftSidebarOpen, setIsLeftSidebarOpen] = useState(true);
|
||||
const [isLeftSidebarOpen, setIsLeftSidebarOpen] = useState(false);
|
||||
// const { currentUser, setCurrentUser } = useUserStore();
|
||||
|
||||
const { setCanvasRef, setVideoRef } = useAppStore();
|
||||
|
|
|
|||
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 226 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 223 KiB |
|
After Width: | Height: | Size: 225 KiB |
|
|
@ -1,4 +1,4 @@
|
|||
from fastapi import FastAPI, UploadFile, File, Form, Depends, HTTPException
|
||||
from fastapi import FastAPI, UploadFile, File, Form, Depends, HTTPException, BackgroundTasks
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy.orm import Session
|
||||
import face_recognition
|
||||
|
|
@ -191,7 +191,7 @@ async def register_student(
|
|||
|
||||
|
||||
@app.post("/checkin")
|
||||
async def checkin(file: UploadFile = File(...), camera_id: str = Form("cam1"), db: Session = Depends(get_db)):
|
||||
async def checkin(background_tasks: BackgroundTasks, file: UploadFile = File(...), camera_id: str = Form("cam1"), db: Session = Depends(get_db)):
|
||||
image_data = await file.read()
|
||||
path = os.path.join(UPLOAD_DIR, "checkin.jpg")
|
||||
with open(path, "wb") as f:
|
||||
|
|
@ -229,7 +229,7 @@ async def checkin(file: UploadFile = File(...), camera_id: str = Form("cam1"), d
|
|||
"""),
|
||||
{
|
||||
"student_id": encoding.id,
|
||||
"time_threshold": now - datetime.timedelta(minutes=5)
|
||||
"time_threshold": now - datetime.timedelta(minutes=0.5)
|
||||
}
|
||||
).fetchone()
|
||||
|
||||
|
|
@ -258,15 +258,14 @@ async def checkin(file: UploadFile = File(...), camera_id: str = Form("cam1"), d
|
|||
# reset pointer
|
||||
file.file.seek(0)
|
||||
|
||||
send_image_res = send_image(
|
||||
id=id_log,
|
||||
file=file,
|
||||
student_name=encoding.name,
|
||||
status=status
|
||||
background_tasks.add_task(
|
||||
send_image,
|
||||
id_log,
|
||||
image_data, # truyền bytes, không phải UploadFile
|
||||
encoding.name,
|
||||
status
|
||||
)
|
||||
|
||||
print(id_log, send_image_res)
|
||||
|
||||
# Insert new checkin
|
||||
db.execute(
|
||||
text("""
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<script
|
||||
type="module"
|
||||
crossorigin
|
||||
src="/camera/static/assets/index-NzXShqcn.js"
|
||||
src="/camera/static/assets/index-Cs3L7CRl.js"
|
||||
></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
from api import send_image
|
||||
|
||||
|
||||
def background_send_image(id_log, file_path, student_name, status):
|
||||
with open(file_path, "rb") as f:
|
||||
send_image(
|
||||
id=id_log,
|
||||
file=f,
|
||||
student_name=student_name,
|
||||
status=status
|
||||
)
|
||||
|
Before Width: | Height: | Size: 219 KiB After Width: | Height: | Size: 222 KiB |
|
After Width: | Height: | Size: 218 KiB |
|
After Width: | Height: | Size: 222 KiB |
|
Before Width: | Height: | Size: 222 KiB After Width: | Height: | Size: 223 KiB |