Commit 26f2107c authored by janithGamage's avatar janithGamage

Merge branch 'master' into IT20402266

parents b522fb5c b67a974b
models/*
!models/
\ No newline at end of file
import multer from "multer";
import videoService from "../service/videoService.js";
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
cb(null, Date.now() + "-" + file.originalname);
},
});
const upload = multer({ storage: storage }).single("video");
export function uploadVideo(req, res) {
upload(req, res, function (err) {
if (err) {
console.error(err);
return res
.status(500)
.send("An error occurred while uploading the video");
}
if (!req.file) {
return res.status(400).send("No video file provided");
}
res.status(200).send({
status: true,
message: "Translated Text",
data: "ආආආආආආආආආ",
});
// videoService
// .processVideo(req.file)
// .then(() => res.status(200).send("Video uploaded successfully"))
// .catch((error) => {
// console.error(error);
// res.status(500).send("An error occurred while processing the video");
// });
});
}
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
"express": "^4.18.2", "express": "^4.18.2",
"jsonwebtoken": "^9.0.0", "jsonwebtoken": "^9.0.0",
"mongoose": "^7.1.1", "mongoose": "^7.1.1",
"multer": "^1.4.5-lts.1",
"nodemailer": "^6.9.1", "nodemailer": "^6.9.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"uuid": "^9.0.0" "uuid": "^9.0.0"
......
import express from "express";
import { uploadVideo } from "../controllers/translate.controller.js";
const router = express.Router();
router.post("/upload", uploadVideo);
export default router;
...@@ -6,6 +6,7 @@ import mongoose from "mongoose"; ...@@ -6,6 +6,7 @@ import mongoose from "mongoose";
//import routes //import routes
import userRoutes from "./routes/user.routes.js"; import userRoutes from "./routes/user.routes.js";
import translateRoutes from "./routes/translate.routes.js";
dotenv.config(); dotenv.config();
const app = express(); const app = express();
...@@ -21,6 +22,7 @@ app.get("/", (req, res) => { ...@@ -21,6 +22,7 @@ app.get("/", (req, res) => {
//implement routes //implement routes
app.use("/rest_node/user", userRoutes); app.use("/rest_node/user", userRoutes);
app.use("/rest_node/ssl", translateRoutes);
const CONNECTION_URL = `mongodb+srv://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@cluster0.dmza8yi.mongodb.net/?retryWrites=true&w=majority`; const CONNECTION_URL = `mongodb+srv://${process.env.DB_USERNAME}:${process.env.DB_PASSWORD}@cluster0.dmza8yi.mongodb.net/?retryWrites=true&w=majority`;
const PORT = process.env.PORT || 5000; const PORT = process.env.PORT || 5000;
...@@ -42,5 +44,5 @@ mongoose ...@@ -42,5 +44,5 @@ mongoose
app.use((err, req, res, next) => { app.use((err, req, res, next) => {
console.error(err.stack); console.error(err.stack);
res.status(500).send('Internal Server Error'); res.status(500).send("Internal Server Error");
}); });
export default function processVideo(videoFile) {
return new Promise((resolve, reject) => {
// Perform video processing tasks here
// Example: store videoFile in a database, generate thumbnails, etc.
// Simulating asynchronous processing
setTimeout(() => {
// Resolve the promise to indicate successful processing
resolve();
}, 2000);
});
}
# Ignore video files
*.mp4
*.avi
*.mov
*.mkv
*.flv
*.wmv
*.mpeg
*.mpg
*.3gp
*.webm
*.vob
*.m4v
*.ts
files/*
!files/
# Created by https://www.toptal.com/developers/gitignore/api/python
# Edit at https://www.toptal.com/developers/gitignore?templates=python
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
# End of https://www.toptal.com/developers/gitignore/api/python
\ No newline at end of file
# TMP-23-029 # TMP-23-029
SLIIT Final Year Project SLIIT Final Year Backend Project
\ No newline at end of file
## Installation
Install dependencies
Python Environment - Python 3.10.11
```bash
pip install -r requirements.txt
```
## Run Locally
Start the server
```bash
uvicorn main:app --reload
```
2023-05-19 00:32:23,385 - INFO - Received request at root endpoint.
2023-05-19 00:32:23,385 - INFO - Received request at root endpoint.
2023-05-19 00:32:48,522 - ERROR - Received request at root endpoint.
2023-05-19 00:32:48,522 - ERROR - Received request at root endpoint.
2023-05-19 23:09:38,565 - INFO - Failed to make predictions. name 'CLASSES' is not defined
2023-05-19 23:09:38,565 - INFO - Failed to make predictions. name 'CLASSES' is not defined
import base64
import os
import cv2
from fastapi import APIRouter, File, HTTPException,UploadFile
import numpy as np
from pydantic import BaseModel
import tensorflow as tf
from core import setup_logger
from services.translate_service import SignLanguagePredictionService
from utils import mappings
router = APIRouter()
logger = setup_logger()
class ImageRequest(BaseModel):
image: UploadFile
# Load your Keras model
model = tf.keras.models.load_model('../ML_Models/sign_language_to_text/models/sign_language_model.h5')
CLASSES = mappings.classes
NUM_CLASSES = len(mappings.classes) # number of classes
IMG_SIZE = 224 # image size
# Instantiate the service class
prediction_service = SignLanguagePredictionService(model, CLASSES, mappings)
@router.post("/upload/video")
async def upload_video(video: UploadFile = File(...)):
try:
file_location = f"files/{video.filename}"
with open(file_location, "wb") as file:
file.write(video.file.read())
return {"text": "ආආආආආආආ"}
except Exception as e:
logger.info(f"Failed to upload file. {e}")
raise HTTPException(
status_code=500,
detail="Failed to upload the video"
)
@router.post('/predict-sign-language/image')
def predict_using_image(image_request: UploadFile = File(...)):
try:
return prediction_service.predict_sign_language(image_request)
except Exception as e:
logger.info(f"Error. {e}")
raise HTTPException(
status_code=500,
detail="Request Failed."
)
@router.post('/predict-sign-language/video')
def predict_using_video(video_request: UploadFile = File(...)):
try:
return prediction_service.predict_sign_language_video(video_request)
except Exception as e:
logger.info(f"Error. {e}")
raise HTTPException(
status_code=500,
detail="Request Failed."
)
\ No newline at end of file
from fastapi import APIRouter
router = APIRouter()
@router.get("/ping")
def test():
# Your code here
return {"pong"}
@router.get("/users")
def get_users():
# Your code here
return {"message": "Get users endpoint"}
@router.post("/users")
def create_user():
# Your code here
return {"message": "Create user endpoint"}
import logging
def setup_logger():
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
# Create a file handler for logging to a file
file_handler = logging.FileHandler('app.log')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
# Create a stream handler for logging to console
stream_handler = logging.StreamHandler()
stream_handler.setLevel(logging.INFO)
stream_handler.setFormatter(formatter)
# Add the handlers to the logger
logger.addHandler(file_handler)
logger.addHandler(stream_handler)
return logger
from fastapi import FastAPI
from controllers import translate_controler, users_controller
from fastapi.responses import RedirectResponse
from fastapi.middleware.cors import CORSMiddleware
from core import setup_logger
app = FastAPI()
logger = setup_logger()
app.include_router(users_controller.router)
app.include_router(translate_controler.router)
# Add cores middleware
origins = [
"http://localhost",
"http://localhost:8080",
]
app.add_middleware(CORSMiddleware,
allow_origins=origins,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"])
@app.get('/')
async def root():
url = app.docs_url or '/docs'
return RedirectResponse(url)
\ No newline at end of file
fastapi
uvicorn
python-multipart==0.0.6
tensorflow==2.12.0
opencv-python==4.7.0.72
\ No newline at end of file
import os
import cv2
import numpy as np
from fastapi import HTTPException, UploadFile
from typing import Dict
import tensorflow as tf
from core import setup_logger
from utils import mappings
logger = setup_logger()
IMG_SIZE = 224 # image size
class SignLanguagePredictionService:
def __init__(self, model, classes, mappings):
self.model = model
self.classes = classes
self.mappings = mappings
def predict_sign_language(self, image_request: UploadFile) -> Dict[str, str]:
try:
file_location = f"files/{image_request.filename}"
with open(file_location, "wb") as file:
file.write(image_request.file.read())
img = cv2.imread(file_location)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (IMG_SIZE, IMG_SIZE))
img = np.array([img], dtype=np.float32) / 255.0
prediction = self.model.predict(img)
class_index = np.argmax(prediction)
class_name = self.classes[class_index]
sinhala_letter = self.mappings.letter_mapping.get(class_name, 'Unknown')
# Delete the image file
os.remove(file_location)
return {'prediction': sinhala_letter}
except Exception as e:
logger.info(f"Failed to make predictions. {e}")
raise HTTPException(
status_code=500,
detail="Failed to make predictions"
)
def predict_sign_language_video(self, video_request: UploadFile) -> Dict[str, str]:
try:
# Create a temporary file to save the video
video_location = f"files/{video_request.filename}"
with open(video_location, "wb") as file:
file.write(video_request.file.read())
# Read the video using OpenCV
video = cv2.VideoCapture(video_location)
predictions = []
frame_count = 0
# Loop through the frames of the video
while frame_count < 20:
success, frame = video.read()
if not success:
break
# Preprocess the frame
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame = cv2.resize(frame, (IMG_SIZE, IMG_SIZE))
frame = np.array([frame], dtype=np.float32) / 255.0
# Make prediction
prediction = self.model.predict(frame)
class_index = np.argmax(prediction)
class_name = self.classes[class_index]
sinhala_letter = self.mappings.letter_mapping.get(class_name, 'Unknown')
# Store the prediction for the frame
predictions.append(sinhala_letter)
frame_count += 1
video.release()
# Delete the video file
os.remove(video_location)
return {'frame_count': frame_count, 'predictions': predictions}
except Exception as e:
logger.info(f"Failed to make predictions. {e}")
raise HTTPException(
status_code=500,
detail="Failed to make predictions"
)
letter_mapping = {
'Ah': 'අ',
'Aah': 'ආ',
'Aeh': 'ඇ',
'Ee': 'ඉ',
'Eeh': 'ඊ',
'Uh': 'උ',
'Uhh': 'ඌ',
'A': 'එ',
'Ae': 'ඒ',
'O': 'ඔ',
'Ohh': 'ඕ',
'K': 'ක්',
'Ig': 'ග්',
'T': 'ටී'
}
classes =['A',
'Aah',
'Ae',
'Aeh',
'Ah',
'Ee',
'Eeh',
'Ig',
'K',
'O',
'Ohh',
'T',
'Uh',
'Uhh']
\ No newline at end of file
...@@ -20,9 +20,9 @@ ...@@ -20,9 +20,9 @@
"dependencies": { "dependencies": {
"@auth0/auth0-spa-js": "^1.22.5", "@auth0/auth0-spa-js": "^1.22.5",
"@emotion/cache": "^11.10.3", "@emotion/cache": "^11.10.3",
"@emotion/react": "^11.10.4", "@emotion/react": "^11.11.0",
"@emotion/server": "^11.10.0", "@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.4", "@emotion/styled": "^11.11.0",
"@fullcalendar/common": "^5.11.3", "@fullcalendar/common": "^5.11.3",
"@fullcalendar/daygrid": "^5.11.3", "@fullcalendar/daygrid": "^5.11.3",
"@fullcalendar/interaction": "^5.11.3", "@fullcalendar/interaction": "^5.11.3",
...@@ -32,8 +32,9 @@ ...@@ -32,8 +32,9 @@
"@fullcalendar/timeline": "^5.11.3", "@fullcalendar/timeline": "^5.11.3",
"@hookform/resolvers": "^2.9.8", "@hookform/resolvers": "^2.9.8",
"@iconify/react": "^4.0.0", "@iconify/react": "^4.0.0",
"@mui/icons-material": "^5.11.16",
"@mui/lab": "^5.0.0-alpha.103", "@mui/lab": "^5.0.0-alpha.103",
"@mui/material": "^5.10.9", "@mui/material": "^5.13.0",
"@mui/x-data-grid": "^5.17.7", "@mui/x-data-grid": "^5.17.7",
"@mui/x-date-pickers": "^5.0.4", "@mui/x-date-pickers": "^5.0.4",
"@react-pdf/renderer": "^3.0.0", "@react-pdf/renderer": "^3.0.0",
...@@ -67,10 +68,12 @@ ...@@ -67,10 +68,12 @@
"react-lazy-load-image-component": "^1.5.5", "react-lazy-load-image-component": "^1.5.5",
"react-map-gl": "^7.0.19", "react-map-gl": "^7.0.19",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.3",
"react-media-recorder": "^1.6.6",
"react-organizational-chart": "^2.2.0", "react-organizational-chart": "^2.2.0",
"react-quill": "^2.0.0", "react-quill": "^2.0.0",
"react-redux": "^8.0.4", "react-redux": "^8.0.4",
"react-slick": "^0.29.0", "react-slick": "^0.29.0",
"react-webcam": "^7.0.1",
"redux": "^4.2.0", "redux": "^4.2.0",
"redux-persist": "^6.0.0", "redux-persist": "^6.0.0",
"rehype-raw": "^6.1.1", "rehype-raw": "^6.1.1",
......
// next
import Head from 'next/head';
// @mui
import {
Box,
Button,
ButtonGroup,
Card,
CardContent,
CardHeader,
Divider,
Grid,
TextField,
IconButton,
Typography,
InputAdornment,
Stack,
Tooltip,
Container,
TextareaAutosize,
Paper,
CircularProgress,
LinearProgress,
} from '@mui/material';
// layouts
import MainLayout from '../layouts/main';
// sections
import {
AboutTranslate,
AboutWhat,
AboutTeam,
AboutVision,
AboutTestimonials,
WebcamStreamCapture,
} from '../sections/slToText';
import { Upload } from 'src/components/upload';
import { useCallback, useRef, useState } from 'react';
import UploadIcon from '@mui/icons-material/Upload';
import EmergencyRecordingIcon from '@mui/icons-material/EmergencyRecording';
import { useSnackbar } from 'notistack';
import useCopyToClipboard from 'src/hooks/useCopyToClipboard';
import Iconify from 'src/components/iconify/Iconify';
import dynamic from 'next/dynamic';
const useReactMediaRecorder = () =>
// eslint-disable-next-line react-hooks/rules-of-hooks
import('react-media-recorder');
// ----------------------------------------------------------------------
AboutPage.getLayout = (page: React.ReactElement) => <MainLayout>{page}</MainLayout>;
// ----------------------------------------------------------------------
export default function AboutPage() {
const [file, setFile] = useState<File | string | null>(null);
const [isUploadFile, setIsUploadFile] = useState<boolean | string | null>(true);
const [videoUrl, setVideoUrl] = useState('');
const [loading, setLoading] = useState(false);
const [value, setValue] = useState('ආආආආආආආආආආආආආආආආ');
const handleDropSingleFile = useCallback(async (acceptedFiles: File[]) => {
const file = acceptedFiles[0];
if (file) {
setFile(
Object.assign(file, {
preview: URL.createObjectURL(file),
})
);
setVideoUrl(URL.createObjectURL(file));
}
}, []);
const checkTranalationTypeForUpload = () => {
if (isUploadFile) {
return 'contained';
} else {
return 'outlined';
}
};
const checkTranalationTypeForRecord = () => {
if (!isUploadFile) {
return 'contained';
} else {
return 'outlined';
}
};
const { enqueueSnackbar } = useSnackbar();
const { copy } = useCopyToClipboard();
const onCopy = (text: string) => {
if (text) {
enqueueSnackbar('Copied!');
copy(text);
}
};
const handleChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => {
setValue(event.target.value);
};
// Video Upload
return (
<>
<Head>
<title>Translate SSL to Text</title>
</Head>
<Container maxWidth="l">
<ButtonGroup disableElevation variant="contained" aria-label="Disabled elevation buttons">
<Button
variant={checkTranalationTypeForUpload()}
startIcon={<UploadIcon />}
onClick={() => {
setIsUploadFile(true);
}}
>
Upload
</Button>
<Button
variant={checkTranalationTypeForRecord()}
startIcon={<EmergencyRecordingIcon />}
onClick={() => {
setIsUploadFile(false);
}}
>
Record
</Button>
</ButtonGroup>
{isUploadFile ? (
<Box sx={{ flexGrow: 1 }}>
<Card>
<CardHeader title="Upload a video containing Sign Language" />
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<Card>
<CardContent>
<Upload
file={file}
onDrop={handleDropSingleFile}
onDelete={() => setFile(null)}
/>
{file && (
<Paper style={{ padding: '20px' }}>
<Typography variant="h5" align="center" gutterBottom>
Preview
</Typography>
<div style={{ marginTop: '20px', textAlign: 'center' }}>
<video src={videoUrl} width="400" controls />
</div>
</Paper>
)}
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={6}>
<Card sx={{ p: 5, minHeight: 300 }}>
<Box display="grid" gap={5}>
<Stack spacing={2}>
{loading ? (
<Card>
<CardContent>
<LinearProgress />
<center>
<Typography variant="h5" component="div" sx={{ marginTop: 2 }}>
Loading...
</Typography>
</center>
</CardContent>
</Card>
) : (
<div>
<Typography variant="overline" sx={{ color: 'text.secondary' }}>
Translated Text
</Typography>
<TextField
fullWidth
value={value}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<Tooltip title="Copy">
<IconButton onClick={() => onCopy(value)}>
<Iconify icon="eva:copy-fill" width={24} />
</IconButton>
</Tooltip>
</InputAdornment>
),
}}
/>
</div>
)}
</Stack>
</Box>
</Card>
</Grid>
<Grid item xs={12} md={12}>
<center>
<Button
variant="contained"
style={{ width: '200px', height: '60px', fontSize: '20px' }}
sx={{
mb: 3,
}}
disabled={loading}
>
Translate
</Button>
</center>
</Grid>
</Grid>
</Card>
</Box>
) : (
// Video Capture
<Box sx={{ flexGrow: 1 }}>
<Card>
<CardHeader title="Upload a video containing Sign Language" />
<Grid container spacing={2}>
<Grid item xs={12} md={6}>
<Card>
<CardContent>
<WebcamStreamCapture />
</CardContent>
</Card>
</Grid>
<Grid item xs={12} md={6}>
<Card sx={{ p: 5, minHeight: 300 }}>
<Box display="grid" gap={5}>
<Stack spacing={2}>
{loading ? (
<Card>
<CardContent>
<LinearProgress />
<center>
<Typography variant="h5" component="div" sx={{ marginTop: 2 }}>
Loading...
</Typography>
</center>
</CardContent>
</Card>
) : (
<div>
<Typography variant="overline" sx={{ color: 'text.secondary' }}>
Translated Text
</Typography>
<TextField
fullWidth
value={value}
onChange={handleChange}
InputProps={{
endAdornment: (
<InputAdornment position="end">
<Tooltip title="Copy">
<IconButton onClick={() => onCopy(value)}>
<Iconify icon="eva:copy-fill" width={24} />
</IconButton>
</Tooltip>
</InputAdornment>
),
}}
/>
</div>
)}
</Stack>
</Box>
</Card>
</Grid>
<Grid item xs={12} md={12}>
<center>
<Button
variant="contained"
style={{ width: '200px', height: '60px', fontSize: '20px' }}
sx={{
mb: 3,
}}
disabled={loading}
>
Translate
</Button>
</center>
</Grid>
</Grid>
</Card>
</Box>
)}
</Container>
</>
);
}
// next
import Head from 'next/head';
// @mui
import { Divider } from '@mui/material';
// layouts
import MainLayout from '../layouts/main';
// sections
import {
AboutTranslate,
AboutWhat,
AboutTeam,
AboutVision,
AboutTestimonials,
} from '../sections/slToText';
// ----------------------------------------------------------------------
AboutPage.getLayout = (page: React.ReactElement) => <MainLayout>{page}</MainLayout>;
// ----------------------------------------------------------------------
export default function AboutPage() {
return (
<>
<Head>
<title>Translate Sinhala Sign Language</title>
</Head>
<AboutTranslate />
</>
);
}
...@@ -32,6 +32,8 @@ export const PATH_PAGE = { ...@@ -32,6 +32,8 @@ export const PATH_PAGE = {
page404: '/404', page404: '/404',
page500: '/500', page500: '/500',
components: '/components', components: '/components',
sslTranslate: '/translate-ssl',
translatePage: '/translate-page',
}; };
export const PATH_DASHBOARD = { export const PATH_DASHBOARD = {
......
import { m } from 'framer-motion';
import { useRef } from 'react';
// @mui
import { useTheme, alpha } from '@mui/material/styles';
import { Box, Stack, Card, Button, Container, Typography, IconButton } from '@mui/material';
// _mock_
import { _carouselsMembers, _socials } from '../../_mock/arrays';
// components
import Image from '../../components/image';
import Iconify from '../../components/iconify';
import Carousel, { CarouselArrows } from '../../components/carousel';
import { MotionViewport, varFade } from '../../components/animate';
// ----------------------------------------------------------------------
export default function AboutTeam() {
const carouselRef = useRef<Carousel>(null);
const theme = useTheme();
const carouselSettings = {
infinite: false,
arrows: false,
slidesToShow: 4,
rtl: Boolean(theme.direction === 'rtl'),
responsive: [
{
breakpoint: 1279,
settings: { slidesToShow: 3 },
},
{
breakpoint: 959,
settings: { slidesToShow: 2 },
},
{
breakpoint: 600,
settings: { slidesToShow: 1 },
},
],
};
const handlePrev = () => {
carouselRef.current?.slickPrev();
};
const handleNext = () => {
carouselRef.current?.slickNext();
};
return (
<Container component={MotionViewport} sx={{ pb: 10, textAlign: 'center' }}>
<m.div variants={varFade().inDown}>
<Typography component="p" variant="overline" sx={{ color: 'text.disabled' }}>
Dream team
</Typography>
</m.div>
<m.div variants={varFade().inUp}>
<Typography variant="h2" sx={{ my: 3 }}>
Great team is the key
</Typography>
</m.div>
<m.div variants={varFade().inUp}>
<Typography
sx={{
mx: 'auto',
maxWidth: 640,
color: 'text.secondary',
}}
>
Minimal will provide you support if you have any problems, our support team will reply
within a day and we also have detailed documentation.
</Typography>
</m.div>
<Box sx={{ position: 'relative' }}>
<CarouselArrows
filled
shape="rounded"
onNext={handleNext}
onPrevious={handlePrev}
leftButtonProps={{
sx: {
left: 24,
...(_carouselsMembers.length < 5 && { display: 'none' }),
},
}}
rightButtonProps={{
sx: {
right: 24,
...(_carouselsMembers.length < 5 && { display: 'none' }),
},
}}
>
<Carousel ref={carouselRef} {...carouselSettings}>
{_carouselsMembers.map((member) => (
<Box
key={member.id}
component={m.div}
variants={varFade().in}
sx={{ px: 1.5, py: 10 }}
>
<MemberCard member={member} />
</Box>
))}
</Carousel>
</CarouselArrows>
</Box>
<Button
variant="outlined"
color="inherit"
size="large"
endIcon={<Iconify icon="ic:round-arrow-right-alt" width={24} />}
sx={{ mx: 'auto' }}
>
View all team members
</Button>
</Container>
);
}
// ----------------------------------------------------------------------
type MemberCardProps = {
member: {
name: string;
role: string | undefined;
avatar: string;
};
};
function MemberCard({ member }: MemberCardProps) {
const { name, role, avatar } = member;
return (
<Card key={name}>
<Typography variant="subtitle1" sx={{ mt: 2, mb: 0.5 }}>
{name}
</Typography>
<Typography variant="body2" sx={{ mb: 2, color: 'text.secondary' }}>
{role}
</Typography>
<Box sx={{ px: 1 }}>
<Image alt={name} src={avatar} ratio="1/1" sx={{ borderRadius: 2 }} />
</Box>
<Stack direction="row" alignItems="center" justifyContent="center" sx={{ p: 2 }}>
{_socials.map((social) => (
<IconButton
key={social.name}
sx={{
color: social.color,
'&:hover': {
bgcolor: alpha(social.color, 0.08),
},
}}
>
<Iconify icon={social.icon} />
</IconButton>
))}
</Stack>
</Card>
);
}
import { m } from 'framer-motion';
// @mui
import { alpha, styled, useTheme } from '@mui/material/styles';
import { Box, Grid, Link, Paper, Rating, Container, Typography } from '@mui/material';
// hooks
import useResponsive from '../../hooks/useResponsive';
// utils
import { bgBlur, bgGradient } from '../../utils/cssStyles';
import { fDate } from '../../utils/formatTime';
// components
import Iconify from '../../components/iconify';
import { MotionViewport, varFade } from '../../components/animate';
// ----------------------------------------------------------------------
const TESTIMONIALS = [
{
name: 'Jenny Wilson',
rating: 5,
dateCreate: new Date(),
content: `Excellent Work! Thanks a lot!`,
},
{
name: 'Cody Fisher',
rating: 5,
dateCreate: new Date(),
content: `It's a very good dashboard and we are really liking the product . We've done some things, like migrate to TS and implementing a react useContext api, to fit our job methodology but the product is one of the best in terms of design and application architecture. The team did a really good job.`,
},
{
name: 'Marvin McKinney',
rating: 5,
dateCreate: new Date(),
content: `Customer support is realy fast and helpful the desgin of this theme is looks amazing also the code is very clean and readble realy good job !`,
},
{
name: 'Darrell Steward',
rating: 5,
dateCreate: new Date(),
content: `Amazing, really good code quality and gives you a lot of examples for implementations.`,
},
{
name: 'Jacob Jones',
rating: 5,
dateCreate: new Date(),
content: `Got a few questions after purchasing the product. The owner responded very fast and very helpfull. Overall the code is excellent and works very good. 5/5 stars!`,
},
{
name: 'Bessie Cooper',
rating: 5,
dateCreate: new Date(),
content: `CEO of Codealy.io here. We’ve built a developer assessment platform that makes sense - tasks are based on git repositories and run in virtual machines. We automate the pain points - storing candidates code, running it and sharing test results with the whole team, remotely. Bought this template as we need to provide an awesome dashboard for our early customers. I am super happy with purchase. The code is just as good as the design. Thanks!`,
},
];
const StyledRoot = styled('div')(({ theme }) => ({
...bgGradient({
color: alpha(theme.palette.grey[900], 0.8),
imgUrl: '/assets/images/about/testimonials.jpg',
}),
textAlign: 'center',
padding: theme.spacing(10, 0),
[theme.breakpoints.up('md')]: {
padding: 0,
height: 840,
textAlign: 'left',
overflow: 'hidden',
},
}));
// ----------------------------------------------------------------------
export default function AboutTestimonials() {
const isDesktop = useResponsive('up', 'md');
return (
<StyledRoot>
<Container component={MotionViewport} sx={{ position: 'relative', height: 1 }}>
<Grid
container
spacing={3}
alignItems="center"
justifyContent={{ xs: 'center', md: 'space-between' }}
sx={{ height: 1 }}
>
<Grid item xs={10} md={4}>
<Box sx={{ maxWidth: { md: 360 } }}>
<m.div variants={varFade().inUp}>
<Typography
component="p"
variant="overline"
sx={{ mb: 2, color: 'text.secondary' }}
>
Testimonials
</Typography>
</m.div>
<m.div variants={varFade().inUp}>
<Typography variant="h2" sx={{ mb: 3, color: 'common.white' }}>
Who love <br />
my work
</Typography>
</m.div>
<m.div variants={varFade().inUp}>
<Typography sx={{ color: 'common.white' }}>
Our goal is to create a product and service that you’re satisfied with and use it
every day. This is why we’re constantly working on our services to make it better
every day and really listen to what our users has to say.
</Typography>
</m.div>
{!isDesktop && (
<Box sx={{ mt: 3, display: 'flex', justifyContent: 'center' }}>
<m.div variants={varFade().inUp}>
<TestimonialLink />
</m.div>
</Box>
)}
</Box>
</Grid>
<Grid
item
xs={12}
md={7}
lg={6}
sx={{
right: { md: 24 },
position: { md: 'absolute' },
}}
>
<Grid container spacing={isDesktop ? 3 : 0} alignItems="center">
<Grid item xs={12} md={6}>
{TESTIMONIALS.slice(0, 3).map((testimonial) => (
<m.div key={testimonial.name} variants={varFade().inUp}>
<TestimonialCard testimonial={testimonial} />
</m.div>
))}
</Grid>
<Grid item xs={12} md={6}>
{TESTIMONIALS.slice(3, 6).map((testimonial) => (
<m.div key={testimonial.name} variants={varFade().inUp}>
<TestimonialCard testimonial={testimonial} />
</m.div>
))}
</Grid>
</Grid>
</Grid>
</Grid>
{isDesktop && (
<Box sx={{ bottom: 60, position: 'absolute' }}>
<m.div variants={varFade().inLeft}>
<TestimonialLink />
</m.div>
</Box>
)}
</Container>
</StyledRoot>
);
}
// ----------------------------------------------------------------------
type TestimonialCardProps = {
testimonial: {
name: string;
rating: number;
content: string;
dateCreate: Date;
};
};
function TestimonialCard({ testimonial }: TestimonialCardProps) {
const theme = useTheme();
const { name, rating, dateCreate, content } = testimonial;
return (
<Paper
sx={{
mt: 3,
p: 3,
color: 'common.white',
...bgBlur({
color: theme.palette.common.white,
opacity: 0.04,
}),
}}
>
<Typography variant="subtitle1" gutterBottom>
{name}
</Typography>
<Typography gutterBottom component="div" variant="caption" sx={{ color: 'grey.500' }}>
{fDate(dateCreate)}
</Typography>
<Rating value={rating} readOnly size="small" />
<Typography variant="body2" sx={{ mt: 1.5 }}>
{content}
</Typography>
</Paper>
);
}
// ----------------------------------------------------------------------
function TestimonialLink() {
return (
<Link href="#" variant="subtitle2" sx={{ display: 'flex', alignItems: 'center' }}>
Read more testimonials
<Iconify icon="ic:round-arrow-right-alt" sx={{ ml: 1 }} />
</Link>
);
}
import { m } from 'framer-motion';
import NextLink from 'next/link';
// @mui
import { styled } from '@mui/material/styles';
import { Stack, Container, Typography, Button } from '@mui/material';
// components
import { MotionContainer, TextAnimate, varFade } from '../../components/animate';
import { PATH_AUTH, PATH_PAGE } from 'src/routes/paths';
// ----------------------------------------------------------------------
const StyledRoot = styled('div')(({ theme }) => ({
position: 'relative',
backgroundSize: 'cover',
backgroundPosition: 'center',
backgroundImage: 'url(/assets/background/overlay_1.svg), url(/assets/images/about/hero.jpg)',
padding: theme.spacing(10, 0),
[theme.breakpoints.up('md')]: {
height: 560,
padding: 0,
},
}));
const StyledContent = styled('div')(({ theme }) => ({
textAlign: 'center',
[theme.breakpoints.up('md')]: {
bottom: 80,
textAlign: 'left',
position: 'absolute',
},
}));
// ----------------------------------------------------------------------
export default function AboutHero() {
return (
<StyledRoot>
<Container component={MotionContainer}>
<StyledContent>
<TextAnimate
text="Translate"
sx={{
color: 'primary.main',
}}
variants={varFade().inRight}
/>
<br />
<Stack spacing={2} display="inline-flex" direction="row" sx={{ color: 'common.white' }}>
<TextAnimate text="Sign" />
<TextAnimate text="Language" />
</Stack>
<m.div variants={varFade().inRight}>
<Typography
variant="h4"
sx={{
mt: 5,
color: 'common.white',
fontWeight: 'fontWeightMedium',
}}
>
You can upload a video containing Sinhala Sign Language &
<br />
convert into text.
</Typography>
</m.div>
<m.div variants={varFade().inRight}>
<NextLink href={PATH_PAGE.translatePage} passHref>
<Button
variant="contained"
sx={{
mt: 5,
}}
>
Start Translation
</Button>
</NextLink>
</m.div>
</StyledContent>
</Container>
</StyledRoot>
);
}
import { m } from 'framer-motion';
// @mui
import { Box, Container, Typography, Stack } from '@mui/material';
// components
import Image from '../../components/image';
import { MotionViewport, varFade } from '../../components/animate';
// ----------------------------------------------------------------------
export default function AboutVision() {
return (
<Container component={MotionViewport} sx={{ mt: 10 }}>
<Box
sx={{
mb: 10,
borderRadius: 2,
overflow: 'hidden',
position: 'relative',
}}
>
<Image src="/assets/images/about/vision.jpg" alt="about-vision" />
<Stack
direction="row"
flexWrap="wrap"
alignItems="center"
justifyContent="center"
sx={{
bottom: { xs: 24, md: 40 },
width: 1,
opacity: 0.48,
position: 'absolute',
}}
>
{['ibm', 'lya', 'spotify', 'netflix', 'hbo', 'amazon'].map((logo) => (
<m.div key={logo} variants={varFade().in}>
<Image
alt={logo}
src={`/assets/icons/brands/ic_brand_${logo}.svg`}
sx={{
m: { xs: 1.5, md: 2.5 },
height: { xs: 24, md: 40 },
}}
/>
</m.div>
))}
</Stack>
</Box>
<m.div variants={varFade().inUp}>
<Typography variant="h3" sx={{ textAlign: 'center', maxWidth: 800, mx: 'auto' }}>
Our vision offering the best product nulla vehicula tortor scelerisque ultrices malesuada.
</Typography>
</m.div>
</Container>
);
}
import { m } from 'framer-motion';
// @mui
import { alpha, useTheme, styled } from '@mui/material/styles';
import { Box, Grid, Button, Container, Typography, LinearProgress } from '@mui/material';
// hooks
import useResponsive from '../../hooks/useResponsive';
// utils
import { fPercent } from '../../utils/formatNumber';
// _mock_
import { _skills } from '../../_mock/arrays';
// components
import Image from '../../components/image';
import Iconify from '../../components/iconify';
import { MotionViewport, varFade } from '../../components/animate';
// ----------------------------------------------------------------------
const StyledRoot = styled('div')(({ theme }) => ({
textAlign: 'center',
paddingTop: theme.spacing(20),
paddingBottom: theme.spacing(10),
[theme.breakpoints.up('md')]: {
textAlign: 'left',
},
}));
// ----------------------------------------------------------------------
export default function AboutWhat() {
const theme = useTheme();
const isDesktop = useResponsive('up', 'md');
const isLight = theme.palette.mode === 'light';
const shadow = `-40px 40px 80px ${alpha(
isLight ? theme.palette.grey[500] : theme.palette.common.black,
0.48
)}`;
return (
<StyledRoot>
<Container component={MotionViewport}>
<Grid container spacing={3}>
{isDesktop && (
<Grid item xs={12} md={6} lg={7} sx={{ pr: { md: 7 } }}>
<Grid container spacing={3} alignItems="flex-end">
<Grid item xs={6}>
<m.div variants={varFade().inUp}>
<Image
alt="our office 1"
src="/assets/images/about/what_1.jpg"
ratio="3/4"
sx={{
borderRadius: 2,
boxShadow: shadow,
}}
/>
</m.div>
</Grid>
<Grid item xs={6}>
<m.div variants={varFade().inUp}>
<Image
alt="our office 2"
src="/assets/images/about/what_2.jpg"
ratio="1/1"
sx={{ borderRadius: 2 }}
/>
</m.div>
</Grid>
</Grid>
</Grid>
)}
<Grid item xs={12} md={6} lg={5}>
<m.div variants={varFade().inRight}>
<Typography variant="h2" sx={{ mb: 3 }}>
What is minimal?
</Typography>
</m.div>
<m.div variants={varFade().inRight}>
<Typography
sx={{
color: (theme) =>
theme.palette.mode === 'light' ? 'text.secondary' : 'common.white',
}}
>
Our theme is the most advanced and user-friendly theme you will find on the market,
we have documentation and video to help set your site really easily, pre-installed
demos you can import in one click and everything from the theme options to page
content can be edited from the front-end. This is the theme you are looking for.
</Typography>
</m.div>
<Box sx={{ my: 5 }}>
{_skills.map((progress) => (
<m.div key={progress.label} variants={varFade().inRight}>
<ProgressItem progress={progress} />
</m.div>
))}
</Box>
<m.div variants={varFade().inRight}>
<Button
variant="outlined"
color="inherit"
size="large"
endIcon={<Iconify icon="ic:round-arrow-right-alt" width={24} />}
>
Check out our work
</Button>
</m.div>
</Grid>
</Grid>
</Container>
</StyledRoot>
);
}
// ----------------------------------------------------------------------
type ProgressItemProps = {
progress: {
label: string;
value: number;
};
};
function ProgressItem({ progress }: ProgressItemProps) {
const { label, value } = progress;
return (
<Box sx={{ mt: 3 }}>
<Box sx={{ mb: 1.5, display: 'flex', alignItems: 'center' }}>
<Typography variant="subtitle2">{label}&nbsp;-&nbsp;</Typography>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
{fPercent(value)}
</Typography>
</Box>
<LinearProgress
variant="determinate"
value={value}
sx={{
'& .MuiLinearProgress-bar': { bgcolor: 'grey.700' },
'&.MuiLinearProgress-determinate': { bgcolor: 'divider' },
}}
/>
</Box>
);
}
.videoContainer {
position: relative;
width: 50%;
padding-top: 56.25%; /* 16:9 aspect ratio */
}
.futuristicVideo {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
outline: none;
background-color: black;
opacity: 0.8;
filter: blur(4px);
transition: opacity 0.5s, filter 0.5s;
}
.futuristicVideo:hover {
opacity: 1;
filter: blur(0);
}
import React, { useEffect, useState } from 'react';
import Webcam from 'react-webcam';
import { Box, Button, Container, Grid, Stack } from '@mui/material';
import StopIcon from '@mui/icons-material/Stop';
import RadioButtonCheckedIcon from '@mui/icons-material/RadioButtonChecked';
import styles from './WebcamStreamCapture.module.css';
const WebcamStreamCapture = () => {
const webcamRef = React.useRef(null);
const mediaRecorderRef = React.useRef(null);
const [capturing, setCapturing] = React.useState(false);
const [recordedChunks, setRecordedChunks] = React.useState([]);
const [mediaBlobUrl, setMediaBlobUrl] = React.useState([]);
const handleStartCaptureClick = React.useCallback(() => {
setRecordedChunks([]);
setMediaBlobUrl([]);
setCapturing(true);
mediaRecorderRef.current = new MediaRecorder(webcamRef.current.stream, {
mimeType: 'video/webm',
});
mediaRecorderRef.current.addEventListener('dataavailable', handleDataAvailable);
mediaRecorderRef.current.start();
}, [webcamRef, setCapturing, mediaRecorderRef]);
const handleDataAvailable = React.useCallback(
({ data }) => {
if (data.size > 0) {
setRecordedChunks((prev) => prev.concat(data));
}
},
[setRecordedChunks]
);
const handleStopCaptureClick = React.useCallback(async () => {
mediaRecorderRef.current.stop();
const blob = new Blob(recordedChunks, {
type: 'video/mp4',
});
const url = await URL.createObjectURL(blob);
console.log(url);
await setMediaBlobUrl(url);
setCapturing(false);
}, [mediaRecorderRef, webcamRef, setCapturing]);
const handleDownload = React.useCallback(() => {
if (recordedChunks.length) {
const blob = new Blob(recordedChunks, {
type: 'video/mp4',
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
document.body.appendChild(a);
a.style = 'display: none';
a.href = url;
a.download = 'user-recording.mp4';
a.click();
window.URL.revokeObjectURL(url);
setRecordedChunks([]);
}
}, [recordedChunks]);
// Styles for camera
const [width, setWidth] = useState(window.innerWidth);
const handleResize = () => {
setWidth(window.innerWidth);
};
useEffect(() => {
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<>
<Grid container spacing={2}>
<Grid item xs={12}>
<center>
<Webcam audio={false} ref={webcamRef} style={{ width: '100%', maxWidth: '500px' }} />
</center>
</Grid>
<Grid item xs={12}>
<center>
{capturing ? (
<Button
onClick={handleStopCaptureClick}
startIcon={<StopIcon />}
color="error"
variant="contained"
>
Stop Capture
</Button>
) : (
<Button
onClick={handleStartCaptureClick}
startIcon={<RadioButtonCheckedIcon />}
color="error"
variant="contained"
>
Start Capture
</Button>
)}
{recordedChunks.length > 0 && (
<Button
onClick={handleDownload}
variant="contained"
sx={{
ml: 1,
}}
>
Download
</Button>
)}
</center>
</Grid>
<Grid item xs={12}>
{recordedChunks.length > 0 && (
<center>
<video src={mediaBlobUrl} controls autoPlay />
</center>
)}
</Grid>
</Grid>
</>
);
};
export default WebcamStreamCapture;
export { default as AboutTranslate } from './AboutTranslate';
export { default as AboutWhat } from './AboutWhat';
export { default as AboutTeam } from './AboutTeam';
export { default as AboutVision } from './AboutVision';
export { default as AboutTestimonials } from './AboutTestimonials';
export { default as WebcamStreamCapture } from './WebcamStreamCapture';
This diff is collapsed.
# Project ID: TMP-23-029 # Project ID: 2023-029
# Project Name: “Sign Language Translation with emotional base multi model,3D Avatar and Adaptive Learning.” # Project Name: “Sign Language Translation with emotional base multi model,3D Avatar and Adaptive Learning.”
## Main Objective ## Main Objective
...@@ -52,10 +52,10 @@ The main objective of this project is to develop a Sign Language Translation Sys ...@@ -52,10 +52,10 @@ The main objective of this project is to develop a Sign Language Translation Sys
### Member: Paranagama R P S D (IT20254384) ### Member: Paranagama R P S D (IT20254384)
**Research Question:** **Research Question:**
- How can hand gestures and emotional gestures in sign language be accurately identified using image sequences, and how can they be translated into text? - How can hand gestures in sign language be accurately identified using image sequences, and how can they be translated into text?
**Objectives:** **Objectives:**
- Pre-process image sequences to isolate hand gestures and facial expressions used in sign language. - Pre-process image sequences to isolate hand gestures used in sign language.
- Utilize action prediction by analyzing frame sequences to accurately identify sign language gestures. - Utilize action prediction by analyzing frame sequences to accurately identify sign language gestures.
- Train a model on sign language data to recognize gestures with high accuracy. - Train a model on sign language data to recognize gestures with high accuracy.
- Integrate the trained model into an application that processes images/video sequences and translates recognized sign language gestures into text. - Integrate the trained model into an application that processes images/video sequences and translates recognized sign language gestures into text.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment